【问题标题】:Does Fragments with setRetainInstance(true) survive process shutdowns?带有 setRetainInstance(true) 的片段是否在进程关闭后仍然存在?
【发布时间】:2013-04-24 05:24:47
【问题描述】:

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

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

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

我在阅读开发者指南 (http://developer.android.com/guide/components/processes-and-threads.html) 时对此感到疑惑:

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

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

这个假设有意义吗?

【问题讨论】:

    标签: android process fragment lifecycle retain


    【解决方案1】:

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

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

    关于您的问题。

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

    希望我能帮助澄清这一点。

    在您的第一条评论之后

    编辑

    关于评论:

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

    关于您的编辑:

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

    你的结论:

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

    很遗憾,没有,因为您混淆了完全独立的概念。

    我会再试一试:

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

    【讨论】:

    • 我编辑了我的问题以进一步澄清它。我主要关心的是当我的托管进程被杀死并从内存中删除时片段实例会发生什么。顺便说一句:onRetainNonConfigurationInstance 已弃用。
    • 非常感谢您的详细回答。这现在更有意义了。
    • 我可能只是补充一下:这实际上是我一开始认为它的工作方式,但是setRetainInstance 的 javadoc 条目说 控制是否在 Activity 重新创建期间保留片段实例(例如来自配置更改)让我感到困惑,因为它只是说重新创建。我读这个好像这会影响片段的任何重新创建。 onRetainNonConfigurationInstance 的条目更加清晰。更不用说你上面的解释了。再次感谢您!
    • @raphw 很高兴您发现我的文字可读。 Android 文档可能会令人困惑(有时甚至会产生误导)。如果我没有从书中学到这一点,我想我会花费数小时试图理解它......
    • @raphw 我所知道的最好的 Android 书籍之一,Android in Practice,第 3.3.2 节。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-24
    • 1970-01-01
    • 1970-01-01
    • 2021-04-13
    相关资源
    最近更新 更多