具有setRetainInstance(true)的片段是否能够在进程关闭后继续存在?

时间:2013-04-30 10:12:45

标签: android process fragment lifecycle retain

考虑到这种情况:如果我创建了一个活动,并且它移至后台并且此活动包含设置为Fragment的{​​{1}},那么Android操作系统可能在某些时候仍然决定关闭活动的托管过程,以释放内存。

然后通过setRetainInstance(true)保存Activity的状态 - 据我所知 - 相关的onSaveInstanceState(Bundle)已写入文件系统,以便在关闭过程中继续存在。 (因此捆绑中对象的要求为Bundle)。稍后,可以通过Serializable在新流程中检索应用程序状态。

相反,我的onRestoreInstanceState(Bundle)包含的变量不一定是Fragment。因此,我想,Serializable无法像Fragment那样存储在磁盘上。那么当进程被杀死时,我的片段会发生什么?

我想知道这阅读开发人员指南(http://developer.android.com/guide/components/processes-and-threads.html):

  

包含当前对用户不可见的活动的流程   (已调用活动的onStop()方法)。这些过程有   没有直接影响用户体验,系统可以杀死他们   在任何时候回收前景,可见或服务的内存   处理。通常有很多后台进程在运行,所以它们   保存在LRU(最近最少使用)列表中以确保   具有用户最近看到的活动的过程是   最后被杀。 如果某个活动实现了其生命周期方法   正确,并保存其当前状态,杀死其进程不会   对用户体验有明显的影响,因为当用户   导航回活动,活动恢复所有活动   可见状态。

我理解上面的 kill ,以便关闭VM实例并将进程的状态写入文件系统(这里是Bundle进行播放)。稍后读取包以恢复该过程。由于片段的保留不涉及生命周期方法,因为我不知道如何保留例如一个指向网络连接的指针(你当然应该永远不会在片段中有这样的指针),我想知道如果在此期间关闭进程,片段是否仍然被恢复。我的结论是,他们肯定需要重新创建,因此生命周期方法应尽可能优先于Bundle

这个假设是否有意义?

1 个答案:

答案 0 :(得分:18)

听起来像你在这里混淆了两个概念。

  • 跨配置更改保存状态不涉及序列化。如果您为setRetainInstance()请求Fragment,那么这意味着它将完全保留在内存中,而不是仅为重新创建以进行配置更改。类似的机制可用于Activity个对象,但是它们需要明确定义将要保存的Object。这可以通过Activity.onRetainNonConfigurationInstance()而不是通过onSaveInstanceStae()
  • 运行
  • 另一种机制涉及序列化,并且可能(可能不总是,不确定)文件系统I / O能够重现状态信息,即使Activity / Fragment被破坏(这是独立发生的)它的托管Process,顺便说一句。这适用于Activity.onSaveInstanceState()Fragment.onSaveInstanceState()
  • 当然,您可以将第二种机制用于第一种机制,从而减慢应用处理配置更改的速度。根据你的内部状态,减速可能是重要的。

关于你的问题。

  • "相反,我的片段允许包含不可序列化的变量。"嗯,你的Activity也是如此。它可以包含不可序列化的对象,可以在配置更改中保存,如上所述。
  • "当进程关闭时,片段无法存储到磁盘,并且必须在恢复活动时重新创建。不,两种机制都可用于两种对象类型。

希望我能为澄清这一点做出贡献。

第一次评论后

修改

关于评论:

  • " onRetainNonConfigurationInstance已被弃用":是的。我之所以提到它是出于演示目的,因为你的问题中有一个特定的措辞。此外,由于Android 2设备目前拥有46%的市场份额(谷歌官方数据),这种方法肯定会在非常长时间内保持不变,不论是否弃用。
  • "我主要担心的是当我的托管进程被杀死并从内存中移除时,片段实例会发生什么?:你的片段实例将从内存中移除当然,它的完整的内部状态自动无法恢复原样。在配置更改的情况下setRetainInstanceState时,完成此操作。 (但请注意,这与 Instance 相关,换言之,与完整对象有关。)

关于你的编辑:

  • 再次,您的Fragment Bundle 存储并恢复到{{1如果您为此目的使用Bundle,那么无论 setRetainInstanceState
  • 是"所有可见状态"将保存为您引用的文字;例如,Fragment.onSaveInstanceState()属性将保存。这不应该是我不知道的错误或功能,但它是事实。但这只是一个侧面评论; UI元素保存大部分相关状态。
  • "进程的状态写入文件系统":不!能够将状态保存到visibility并实际实现保存其状态的对象状态将保存在Bundle中,意味着如果您希望Bundle保存某些州信息,您必须自己提供此类信息。此外,再次:,这不仅与杀死进程有关,还与删除不可见的FragmentActivity个对象有关;就像显示的最后一个活动一样 - Fragment可能会保持活力。
  • "读取包以恢复进程":不,Process将被读取将其传递给Activity和/或Fragment对象的重构,在此过程中自动完成 nothing (除了保存状态的库对象也恢复其状态),但 Android & #34;履历" "流程"来自这些Bundle s。
  • &#34;由于片段的保留与生命周期方法无关&#34;:同样,我认为你正在混淆这两个概念。 &#34;保留&#34; <{1}}仅在配置更改时执行 _IF_您是通过Bundle请求的,但我们主要谈论的是在此处Fragment创建setRetainInstance个对象,其中 涉及Google记录的生命周期方法。
  • &#34;我不知道如何保留,例如指向网络连接的指针&#34;:同样,这必须是基于您的混淆的声明。当然,您可以在配置更改时保留对网络连接的引用(按照Fragment的要求),因为当发生这种情况时,所有内容都会保留在内存中。此外,即使您的Bundle被删除(因为它变得不可见)并且您的进程仍在那里(因为它显示了下一个Activity),您也可以(并且应该)保留对重新创建的对象的引用您的setRetainInstance对象中的网络连接,例如网络连接,只要您的进程存在(或多或少),就会存在。当您的整个应用被Android杀死时,只有 才会丢失所有内容,但我们正在讨论的序列化经常发生

你的结论:

  

我得出结论,他们肯定需要重新创建,因此生命周期方法应尽可能优于setRetainInstance(true)。这个假设有意义吗?

不幸的是,因为你混合了完全独立的概念。

我将最后一次尝试:

  • 您需要在Fragment对象中的整个应用中保留网络连接引用,因为如果您是从头开始创建它,那将是一种糟糕的用户体验整个应用程序的基础。
  • 只有Android杀死了你的应用,你的Application对象才会死亡。
  • 当用户在您的应用中向前移动时,您的ApplicationApplication个对象将定期从您的应用中删除。
  • 当用户按下&#34;返回&#34;时,Android将使用生命周期方法从Activity重新创建FragmentActivity个对象。如果你有重新创建内部状态的昂贵计算,那么在Bundle中保存一些东西是有意义的。您可以在没有Fragment机制的情况下生活,因为Android会始终保存Bundle,因此如果您不做任何事情,那么您将在没有保存状态的情况下启动。
  • 当发生配置更改时,Android可让您通过在配置更改中保留内存中的对象来优化用户体验。在这里,Bundle生命周期方法得到了解决,并且由您的实现来有效地使用保存的数据。对于Intent s,如果你设置它,Activity Fragment`将在内存中的配置更改中存活。