了解Fragment的setRetainInstance(boolean)


341

从文档开始:

public void setRetainInstance(布尔值保留)

控制是否在活动重新创建期间保留片段实例(例如,通过配置更改)。这只能与不在后堆栈中的片段一起使用。如果设置,则重新创建活动时片段的生命周期将略有不同:

  • onDestroy()不会被调用(但是onDetach()仍然会被调用,因为该片段正在从其当前活动中分离出来)。
  • 由于不会重新创建片段,因此不会调用onCreate(Bundle)。
  • onAttach(Activity)和onActivityCreated(Bundle)仍将被调用。

我有一些疑问:

  • 片段是否还保留其视图,还是会在配置更改时重新创建该视图?“保留”到底是什么意思?

  • 用户离开活动时,碎片会被破坏吗?

  • 为什么它对后堆栈上的片段不起作用?

  • 在哪些使用案例中使用此方法有意义?


Answers:


347

首先,检查出我的岗位上保留碎片。这可能会有所帮助。

现在回答您的问题:

片段是否还保留其视图状态,还是会在配置更改时重新创建该视图状态-“保留”的确切含义是什么?

是的,Fragment的状态将在配置更改中保留。具体来说,“保留”是指片段不会在配置更改时被破坏。也就是说,即使配置更改导致基础结构被破坏,Fragment也将保留Activity

用户离开活动时,碎片会被破坏吗?

就像Activitys 一样,Fragment当内存资源不足时,s可能会被系统破坏。是否让片段在配置更改期间保留其实例状态,将对Fragment离开s后系统是否销毁s 没有影响Activity。如果离开Activity(即按home键),则FragmentS可以或可以不被破坏。如果Activity通过按“后退”按钮离开,(因此,调用finish()并有效销毁Activity),则所有Activity连接的Fragments也将被销毁。

为什么它对后堆栈上的片段不起作用?

为什么不支持它可能有多种原因,但是对我来说,最明显的原因是,该方法Activity持有对的引用FragmentManager,并FragmentManager管理后退堆栈。也就是说,无论您选择保留Fragment还是不保留,配置更改都会破坏Activity(并因此而导致FragmentManager的堆栈)。之所以不起作用的另一个原因是,如果允许保留的碎片未保留的碎片都被允许存在于同一backstack中,那么事情可能会变得棘手。

在哪些使用案例中使用此方法有意义?

保留的片段对于在活动实例之间传播状态信息(尤其是线程管理)非常有用。例如,一个片段可以充当Thread或实例的主机,以AsyncTask管理其操作。有关更多信息,请参阅我的博客文章

总的来说,我会把它当作onConfigurationChangedActivity...一样使用。不要仅仅因为你太懒而无法正确实现/处理方向改变,就把它当作创可贴。仅在需要时使用它。


37
视图对象不会保留,它们总是在配置更改时被销毁。
Markus Junginger

103
据我所知,如果有setRetainInstance(true),则Fragmentjava对象及其所有内容都不会在旋转时被破坏,但是重新创建视图。即onCreatedView()再次调用。Activities自从Android 1.0 开始,这基本上就是应该使用的方式。我认为使用它不是“懒惰”,或者使用它不是“适当”的。实际上,我看不到为什么它不是默认值,或者为什么您要取消默认值。
Timmmm 2012年

24
我找到了您的解释:“为什么它不能与后堆栈中的片段一起使用?” 很难理解。但也许我
很蠢

13
@dierre活动可以通过多种方式销毁。例如,如果您单击“返回”,则该活动将被销毁。如果单击“主页”,则该活动将停止,并且将来在内存不足时可能会被销毁。保留Fragments仅在配置更改中保留,配置更改将销毁并立即重新创建基础活动。在其他所有破坏活动的情况下,保留的碎片也将被破坏。
Alex Lockwood

3
@AlexLockwood您能否确认以下内容:即使setRetainInstance(true)使用了它,仍然必须实现自己的持久性(savedInstanceState或其他方式)才能处理所有情况:例如,“ home键,旋转,返回到应用程序”使用构造函数重新创建我的片段调用,丢失所有状态变量。我有一个AsyncTaskas成员变量,这就是为什么我要保留的原因,现在,如果我想让它工作,我将被迫停止任务,保存状态并在用户返回时恢复。因此,总而言之,这只是帮助旋转的一种快速方法,但通常没有用。
TWiStErRob

28

setRetaininstance仅在activity由于配置更改而销毁并重新创建您的计算机时,此命令才有用,因为在调用时会保存实例onRetainNonConfigurationInstance。也就是说,如果旋转设备,保留的片段将保留在那里(它们不会被销毁和重新创建。),但是当运行时终止活动以回收资源时,将一无所有。当您按下“后退”按钮并退出活动时,一切都将被销毁。

通常我使用此功能来保存更改方向的时间,比如说我已经从服务器下载了一堆位图,每个位图都是1MB,当用户不小心旋转设备时,我当然不想再做所有的下载工作。我创建了一个Fragment保存我的位图并将其添加到管理器并调用setRetainInstance,即使屏幕方向发生变化,所有位图仍然存在。


您是否创建“仅数据”片段(不带任何小部件),就像保留位图一样,或者这些片段也可以具有小部件?我读过一些有关当片段包含与上下文/活动相关的东西时产生内存泄漏的危险的东西
hgoebl 2015年

该框架将为您清除mActivity参考。但是我不知道这种情况下运行时是否还会清除片段实例中的小部件。请尝试一下或深入研究源代码。
–suitianshi

何时可以使用setRetaininstance的一个很好的例子
Mu Sa

12

SetRetainInstance(true)允许片段幸存。其成员将在配置更改(例如旋转)期间保留。但是当在后台杀死活动时,它仍然可能被杀死。如果后台包含的活动被系统杀死,则应由您在onSaveInstanceState上正确处理的系统保存它的instanceState。换句话说,将始终调用onSaveInstanceState。尽管如果SetRetainInstance为true且片段/活动尚未被杀死,则不会调用onCreateView,但如果它被杀死并试图带回,则仍将调用它。

以下是对android活动/片段希望有所帮助的一些分析。 http://ideaventure.blogspot.com.au/2014/01/android-activityfragment-life-cycle.html


7
我肯定看到旋转屏幕时在保留的片段上再次调用了onCreateView。
aij 2015年

这是您自己的博客链接吗?如果是这样,您应该明确说明。
Flexo

4

setRetainInstance()-不建议使用

作为片段版本1.3.0-alpha01

片段上的setRetainInstance()方法已被弃用。随着ViewModels的引入,开发人员拥有了一个特定的API,用于保留可以与Activity,Fragments和Navigation图相关联的状态。这使开发人员可以使用正常的,未保留的Fragment并将他们想要保留的特定状态分开,避免泄漏的共同原因,同时保留单个创建和销毁保留状态的有用属性(即ViewModel的构造函数)以及收到的onCleared()回调)。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.