13

考虑到这种情况:如果我创建了一个活动并且它移动到后台并且这个活动包含一个Fragment设置为setRetainInstance(true)然后Android操作系统可能在某些时候仍然决定关闭活动的托管进程以释放内存。

然后Activity's 的状态通过onSaveInstanceState(Bundle)where - 据我了解 - 将相关Bundle内容写入文件系统并保存到文件系统以在进程关闭后继续存在。(因此捆绑中的对象的要求是Serializable)。稍后,应用程序状态可以通过onRestoreInstanceState(Bundle).

相反,Fragment允许 my 包含不一定是Serializable. 因此,我认为,Fragment不能像现在这样存储在磁盘上Bundle。那么当进程被杀死时我的片段会发生什么?

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

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

我理解上面的杀戮使得VM实例被关闭并且进程的状态被写入文件系统(这里Bundle开始发挥作用)。稍后读取捆绑包以恢复该过程。由于片段的保留与生命周期方法无关,并且由于我不知道如何保留例如指向网络连接的指针(无论如何,您当然不应该在片段中有这样的指针),我想知道片段是否如果在此期间关闭进程,它们仍然会恢复。我得出的结论是,它们肯定需要重新创建,因此应尽可能优先使用生命周期方法setRetainInstance(true)

这个假设有意义吗?

4

1 回答 1

21

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

  • 跨配置更改保存状态不涉及序列化。如果您请求setRetainInstance()thenFragment这意味着它将完全保留在内存中,并且不会仅为配置更改而重新创建。类似的机制可用于Activity对象,但它们需要明确定义Object要保存的对象。这可以通过Activity.onRetainNonConfigurationInstance()而不是通过onSaveInstanceStae()
  • Activity另一种机制涉及序列化和可能(可能并不总是,不确定)文件系统 I/O,即使/Fragment被破坏(这与它的托管无关,顺便说一句),也能够重现状态信息Process。这通过Activity.onSaveInstanceState()和工作Fragment.onSaveInstanceState()
  • 当然,您可以将第二种机制用于第一种机制,从而减慢您的应用程序处理配置更改的方式。根据您的内部状态,经济放缓可能是微不足道的。

关于你的问题。

  • “相比之下,我的片段允许包含不可序列化的变量。” 好吧,你的Activity. 它可以包含不可序列化的对象,这些对象可以在如上所述的配置更改中保存。
  • “当进程关闭时,片段不能存储到磁盘,必须在活动恢复时重新创建。” 不,这两种机制都适用于两种对象类型。

希望我能有助于澄清这一点。

在您的第一条评论后编辑。

关于评论:

  • onRetainNonConfigurationInstance已弃用”:是的。由于您的问题中的特定措辞,我出于演示目的提到了它。此外,根据今天的 Android 2 设备拥有 46% 的市场份额(谷歌官方数据),这种方法肯定会存在长时间,无论是否被弃用。
  • “我主要关心的是,当我的托管进程被杀死并从内存中删除时,片段实例会发生什么”:您的片段实例将从内存中删除,当然不可能以其完整的内部恢复原样自动状态。仅当您在配置更改的情况下才会这样做。setRetainInstanceState(但请注意,这与Instance相关,换句话说,与完整对象有关。)

关于您的编辑:

  • 再一次,的,您Fragment的 'sBundle 被存储和恢复到/从Bundle 无论setRetainInstanceState您是否Fragment.onSaveInstanceState()用于此目的,所有有意义的事情。
  • 将“所有可见状态”保存为您引用的声明文本是不正确的;例如,该visibility属性将不会被保存。我不知道这应该是错误还是功能,但这是事实。但这只是一个旁白;UI 元素保存它们的大部分相关状态。
  • “进程的状态写入文件系统”:不!能够将其状态保存到 a并实际实现保存其状态的对象的状态将保存在 a 中,这意味着如果您希望保存一些状态信息,您必须自己提供此类信息。另外,再次:,这不仅与终止进程有关,还与删除和不可见的对象有关;就像显示的最后一个活动一样 -很可能还活着。BundleBundleFragmentActivityFragmentProcess
  • “为恢复进程读取捆绑包”:不,Bundle将被读取以将其传递给 Activity 和/或 Fragment 对象的重建,在此过程中没有自动执行任何操作(除了保存其状态的库对象也恢复他们的状态),但Android不会从这些s“恢复”“进程” 。Bundle
  • “由于片段的保留与生命周期方法无关”:我认为您再次混淆了这两个概念。a 的“保留”Fragment仅在您通过 _IF_ 请求的配置更改执行,但我们主要讨论从 a 重新创建对象,这确实涉及 Google 记录的生命周期方法。setRetainInstanceFragmentBundle
  • “我不知道如何保留例如指向网络连接的指针”:同样,这必须是基于您的混淆的声明。当然,您可以在配置更改时(根据请求setRetainInstance)保留对网络连接的引用,因为发生这种情况时,所有内容都简单地保存在内存中。此外,即使您Fragment被删除(因为它变得不可见)并且您的进程仍然存在(因为它显示下一个活动),您可以(并且应该)保留对重新创建昂贵的对象的引用,例如网络连接,在您的Application对象中,只要您的进程存在(或多或少),它就存在。只有当您的整个应用程序被 Android 杀死时,您才会失去一切,但是我们正在讨论的序列发生得更频繁

你的结论:

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

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

我会做最后的尝试:

  • 您需要在对象中保留整个应用程序所需的网络连接Application引用,因为如果您在整个应用程序中定期从头开始创建它,这将是一个糟糕的用户体验。
  • 只有当 Android 杀死您的应用程序时,您的Application对象才会死亡。
  • 当用户在您的应用程序中前进时,您的Activity和对象将定期从您的应用程序中删除。Fragment
  • Activity当用户按下“返回”时, Android 将使用生命周期方法从 s重新创建Fragment对象。Bundle如果您需要进行昂贵的计算以重新创建内部状态,则将某些内容保存在 Bundle 中是有意义的。你可以没有这种Bundle机制,因为 Android 总是会保存,Intent所以如果你不做任何事情,那么你将在没有保存状态的情况下开始。
  • 发生配置更改时,Android 允许您通过在配置更改期间将对象保留在内存中来优化用户体验。在这里,Activity涉及到生命周期方法,有效使用保存的数据取决于您的实现。对于Fragments,这是setRetainInstance' comes into play: YourFragment` 将在内存中的配置更改后幸存下来的地方,如果你设置它的话。
于 2013-04-30T10:44:14.330 回答