从文档开始:

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.

我有几个问题:

片段是否也保留它的视图,或者在配置更改时重新创建视图?“保留”到底是什么意思? 当用户离开活动时,片段会被销毁吗? 为什么它不能与后面堆栈上的片段一起工作? 在哪些用例中使用这种方法是有意义的?


首先,看看我关于留存碎片的帖子。这可能会有帮助。

现在来回答你们的问题:

片段是否也保留它的视图状态,或者在配置更改时重新创建视图状态——究竟“保留”的是什么?

是的,片段的状态将在配置更改期间被保留。具体来说,“保留”意味着片段不会在配置更改时被销毁。也就是说,即使配置更改导致底层活动被销毁,片段也将被保留。

当用户离开活动时,片段会被销毁吗?

Just like Activitys, Fragments may be destroyed by the system when memory resources are low. Whether you have your fragments retain their instance state across configuration changes will have no effect on whether or not the system will destroy the Fragments once you leave the Activity. If you leave the Activity (i.e. by pressing the home button), the Fragments may or may not be destroyed. If you leave the Activity by pressing the back button (thus, calling finish() and effectively destroying the Activity), all of the Activitys attached Fragments will also be destroyed.

为什么它不能与后面堆栈上的片段一起工作?

There are probably multiple reasons why it's not supported, but the most obvious reason to me is that the Activity holds a reference to the FragmentManager, and the FragmentManager manages the backstack. That is, no matter if you choose to retain your Fragments or not, the Activity (and thus the FragmentManager's backstack) will be destroyed on a configuration change. Another reason why it might not work is because things might get tricky if both retained fragments and non-retained fragments were allowed to exist on the same backstack.

在哪些用例中使用这种方法是有意义的?

保留片段对于跨活动实例传播状态信息(尤其是线程管理)非常有用。例如,一个片段可以作为一个线程或AsyncTask实例的宿主,管理它的操作。更多信息请参见我的博客文章。

一般来说,我会把它类似于使用onConfigurationChanged与一个活动…不要仅仅因为你懒得正确地实现/处理方向变化就把它当作一个创可贴。只在你需要的时候使用它。


SetRetainInstance(true) allows the fragment sort of survive. Its members will be retained during configuration change like rotation. But it still may be killed when the activity is killed in the background. If the containing activity in the background is killed by the system, it's instanceState should be saved by the system you handled onSaveInstanceState properly. In another word the onSaveInstanceState will always be called. Though onCreateView won't be called if SetRetainInstance is true and fragment/activity is not killed yet, it still will be called if it's killed and being tried to be brought back.

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


setRetaininstance仅在您的活动由于配置更改而被销毁和重新创建时有用,因为实例是在调用onRetainNonConfigurationInstance期间保存的。也就是说,如果您旋转设备,保留的片段将保留在那里(它们不会被销毁和重新创建),但当运行时杀死活动以回收资源时,什么都不留下。当你按下后退按钮并退出活动时,一切都被破坏了。

通常我用这个函数来保存方向改变时间。假设我从服务器上下载了一堆位图,每个位图都是1MB,当用户不小心旋转了他的设备时,我当然不想再做所有的下载工作。所以我创建了一个片段保存我的位图,并将其添加到管理器,并调用setRetainInstance,所有的位图仍然在那里,即使屏幕方向改变。


setRetainInstance(boolean)在你想要某个组件不绑定到Activity生命周期时很有用。这种技术被rxloader用来“为rxjava的Observable处理Android的活动生命周期”(我在这里找到了)。


setRetainInstance() -已弃用

As Fragments Version 1.3.0-alpha01

The setRetainInstance() method on Fragments has been deprecated. With the introduction of ViewModels, developers have a specific API for retaining state that can be associated with Activities, Fragments, and Navigation graphs. This allows developers to use a normal, not retained Fragment and keep the specific state they want retained separate, avoiding a common source of leaks while maintaining the useful properties of a single creation and destruction of the retained state (namely, the constructor of the ViewModel and the onCleared() callback it receives).