从一个文档:
public void setRetainInstance (boolean retain)
Control whether a fragment instance is retained across Activity re-creation (such as from a configuration change). This can only be used with fragments not in the back stack. If set, the fragment lifecycle will be slightly different when an activity is recreated:
-
onDestroy() will not be called (but onDetach() still will be, because the fragment is being detached from its current activity).
-
onCreate(Bundle) will not be called since the fragment is not being re-created.
-
onAttach(Activity) and onActivityCreated(Bundle) will still be called.
我有一些问题:
- 同样的问题和好的信息:为什么使用fragment setretaininstance(布尔值)?
首先,看看我关于保留片段的帖子。也许有帮助。
现在回答您的问题:
Does the fragment also retain its view state, or will this be recreated on configuration change - what exactly is"retained"?
是的,Fragment的状态将在配置更改期间保留。具体来说,"保留"意味着在配置更改时不会销毁片段。也就是说,即使配置更改导致底层Activity被破坏,Fragment也将被保留。
Will the fragment be destroyed when the user leaves the activity?
就像Activitys一样,当内存资源不足时,系统可能会破坏Fragments。无论您的片段是否在配置更改中保留其实例状态,都不会影响系统在离开Activity后是否会销毁Fragment。如果您离开Activity(即按下Home(主页)按钮),Fragment可能会或不会被销毁。如果按后退按钮离开Activity(因此,调用finish(),并有效地销毁Activity,则所有Activity附加的Fragment也将被销毁。
Why doesn't it work with fragments on the back stack?
可能有多种原因不支持它,但对我来说最明显的原因是Activity引用了FragmentManager,FragmentManager管理了backbackback。也就是说,无论你是否选择保留你的Fragments,Activity(因此FragmentManager的backbackback)在配置更改时都会被破坏。另一个可能不起作用的原因是,如果保留的片段和未保留的片段都允许存在于同一个backstack上,那么事情可能会变得棘手。
Which are the use cases where it makes sense to use this method?
保留的片段对于跨活动实例传播状态信息(尤其是线程管理)非常有用。例如,一个片段可以作为一个主机,例如Thread或AsyncTask的实例来管理其操作。有关详细信息,请参阅我关于此主题的博客文章。
一般来说,我会把它和使用onConfigurationChanged和Activity的方法相似。不要仅仅因为你太懒而不能正确地实现/处理方向改变就把它当作创可贴。只在需要时使用。
- 非常感谢您的解释,我会慢慢复习的:)
- 视图对象不被保留,它们总是在配置更改时被销毁。
- @绿色机器人甚至在碎片里?(不管怎样,我的意思是"国家"……不是"View"。
- 据我所知,如果你有EDOCX1,1,EDCOX1,2,Java对象,并且它的所有内容在旋转时不会被破坏,但是视图被重新创建。这就是又一次调用onCreatedView()。这基本上是自android 1.0以来它应该与Activities合作的方式。我不认为使用它是"懒惰的",也不认为使用它是"不恰当的"。事实上,我不明白为什么它不是默认的,或者为什么你会想要它关闭。
- 我找到了你对"为什么它不能和后堆栈上的片段一起工作"的解释。很难理解。但也许我很笨:(
- @Alexlockwood你能解释一下为什么用它来管理方向变化是不好的吗?我已经测试了这两种方法,它似乎可以为你做任何事情而不需要复杂。我不明白为什么。
- @克劳齐埃看到这个链接。
- 够公平的,THX
- @Alexlockwood你能帮我吗?stackoverflow.com/questions/17161159/…
- @Alexlockwood你提到,"如果碎片的布局膨胀/创建成本很高,并且你不希望每次用户改变设备的方向时都必须创建它,那么让碎片保持其状态也可能是有意义的。"不是这样会导致活动上下文的内存泄漏吗?您的(保留的)视图将保留对原始活动的引用,以防止其被垃圾收集。当然,您可以给它一个应用程序上下文,但这对我来说并不实际。你能解释一下这种情况吗?
- @是的,你是对的。我想我第一次写那篇文章的时候一定错过了。只有在活动和片段都被保留的情况下,您才能这样做。由于这个原因,您通常不想保留UI片段…我把答案中的那部分都编辑了出来,谢谢你引起我的注意。:)
- @Alexlockwood是否可以替代Mantain状态的应用程序模式?比如获取一个存储库来插入/获取数据。它看起来不像,但因为它能在这种活动中生存…
- @Diere"应用程序模式"是什么意思?您的意思是在Application的子类中保存状态吗?如果是这样,我想这是两个完全不同的概念(因为Application对象在整个应用程序的生命周期中都存在,但是保留的Fragment对象只存在于其宿主Activity对象没有被破坏/完成的情况下。
- @是的,我指的是。TNX我没有得到的是"也就是说,即使配置更改导致底层活动被破坏,碎片也将被保留。"所以我认为它可以在其活动中生存下来。
- @一个活动可以通过多种方式被破坏。例如,如果单击"上一步",活动将被销毁。如果单击"主页",活动将停止,将来某个时间内存不足时可能会被破坏。保留的Fragment只在配置更改时保留,在更改过程中要销毁并立即重新创建底层活动。在所有其他活动被破坏的情况下,保留的碎片也将被破坏。
- @Alexlockwood谢谢你Alex。
- @来自stackoverflow.com/questions/12640316/…的alexlockwood,当方向改变时,将调用fragment.onDestroyView(),然后在fragment.onCreateView()附加到新活动后再次调用。因此,如果片段包含一些视图和方向更改,那么片段用来重新创建它视图的上下文是什么(旧的活动上下文或新的活动上下文)。如果使用新的活动上下文,则不应泄漏内存。
- 我们刚刚测试了是否确实不能将保留的片段添加到后堆栈中,但是它起作用了。我们也注意到医生说这是不可能的,但在实践中似乎是可行的。有人真的试过这个吗?
- @Alexlockwood你好,我看到了你关于碎片的帖子,看起来碎片是你生来就有的:)实际上我面临着一个严重的问题。我的用例位于活动的顶部,我用hide()和add()方法+addTobackStack()链接了打开的片段。现在,当我的进程被终止,我再次打开应用程序。我可以看到我最后的片段(没关系),也可以看到我隐藏的片段(真的很痛)。你能帮我怎么应付这种情况吗?从而保留用户体验。谢谢
- @穆罕默德巴尔,你的情况如何涉及到setRetainInstance()?
- @亚历克洛克伍德没有这么说!
- 在这种情况下需要你的建议。
- 虽然fragmentmanager是重新创建的,但是backstack似乎不是,或者其中的实体是从某个地方添加回来的。
- 让我恼火的是,我必须去谷歌的博客了解onRetainInstance,而不是Android官方文档!
- 上面提到过,但这里有一些附加信息,显示了在某些情况下,系统仍然可以重新创建保留的片段。"不要保留活动的开发选项,打开应用程序,按Home,打开概述列表(以前是Recents),然后再次按应用程序。你会得到这个:gist.github.com/jameswald/b091055a213ac994f274
- @Alexlockwood能否确认一下:即使使用了setRetainInstance(true),仍然需要实现自己的持久性(savedInstanceState或其他),才能处理所有场景:例如,"Home key,Rotate,Back to app"用构造函数调用重新创建我的片段,丢失所有状态变量。我有一个EDOCX1[4]作为成员变量,这就是我想要保留的原因,现在,如果我想让它工作,我必须停止任务,保存状态,并在用户返回时恢复。所以总而言之,这只是一个快速的方法来帮助旋转,但在一般情况下是无用的。
- 您仍然需要重写onSaveInstanceState()以保存应用程序的状态。setRetainInstance(true)只保留配置更改中的片段…尽管如此,活动/片段仍可能因其他原因而被破坏(即用户按下Home按钮,随后由于内存不足等原因导致进程终止)。
- 另一块Alex Lockwood宝石:)
- 我想知道,当任何片段的默认行为(未添加到后堆栈中)出现时,为什么要对片段使用setretaininstance(true)?完全一样吗?"当配置更改发生时,旧片段不会被破坏——当重新创建时,它会将自己添加回活动中。这是一个巨大的痛苦在后方大多数时间"stackoverflow.com/questions/8474104/…
- 试过了,但没有得到第三个问题的预期结果。
- @索瑟顿:那个答案的措辞是错误的:看它的评论。它现在已被编辑为删除"未销毁"字样。当setRetainInstance为false时,添加回新活动的是从旧片段的保存状态创建的新片段。
只有当您的Activity由于配置更改而被破坏和重新创建时,setRetaininstance才有用,因为在调用onRetainNonConfigurationInstance期间保存了实例。也就是说,如果旋转设备,保留的片段将保留在那里(它们不会被销毁和重新创建),但是当运行时终止活动以回收资源时,什么也不会留下。当您按下后退按钮并退出活动时,一切都将被破坏。
通常我使用这个功能来节省方向改变的时间,比如说我从服务器上下载了一堆位图,每一个都是1MB,当用户不小心转动他的设备时,我肯定不想再做所有的下载工作,所以我创建了一个Fragment,拿着我的位图,把它添加到管理器中,然后调用setRetaininstance,所有的位图即使屏幕方向改变,S仍然存在。
- 您是否创建"仅数据"片段(没有任何小部件)作为位图的持有者,或者这些片段也可以有小部件?我读过一些关于当片段包含与上下文/活动相关的内容时产生内存泄漏的危险的文章…
- 框架将为您清除mActivity引用。但我不知道在这种情况下,运行时是否也会清除片段实例中的小部件。请尝试一下,或者深入到源代码中。
- 我们什么时候可以使用setretaininstance的好例子
setRetainInstance(true)允许片段存活。其成员将在配置更改(如旋转)期间保留。但当活动在后台被杀死时,它仍然可能被杀死。如果后台包含的活动被系统终止,则应该由正确处理OnSaveInstanceState的系统保存其InstanceState。换句话说,将始终调用OnSaveInstanceState。尽管如果setRetainInstance为true且片段/活动尚未终止,则不会调用onCreateView,但如果它已被终止并试图恢复,则仍将调用onCreateView。
下面是对Android活动/片段的一些分析,希望它能有所帮助。网址:http://ideaventure.blogspot.com.au/2014/01/android-activityfragment-life-cycle.html
- 旋转屏幕时,我肯定看到OnCreateView在保留的片段上再次被调用。
- 这个链接是你自己的博客吗?如果是这样的话,你应该说清楚。
当您希望拥有一些与活动生命周期无关的组件时,setRetainInstance(布尔值)非常有用。例如,RxLoader使用这种技术"处理RxJava的Observable的Android活动生命周期"(我在这里找到)。