ChatGPT解决这个技术问题 Extra ChatGPT

理解 Fragment 的 setRetainInstance(boolean)

从文档开始:

public void setRetainInstance (boolean retain) 控制是否在 Activity 重新创建时(例如从配置更改)保留片段实例。这只能与不在后台堆栈中的片段一起使用。如果设置,片段生命周期将在重新创建活动时略有不同:不会调用 onDestroy() (但仍然会调用 onDetach(),因为片段正在与其当前活动分离)。 onCreate(Bundle) 不会被调用,因为片段没有被重新创建。 onAttach(Activity) 和 onActivityCreated(Bundle) 仍将被调用。

我有一些问题:

片段是否也保留其视图,或者会在配置更改时重新创建? “保留”究竟是什么意思?

当用户离开activity时,fragment会被销毁吗?

为什么它不适用于后堆栈上的片段?

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

具有良好信息的类似问题:Why use Fragment#setRetainInstance(boolean)?
多窗口(API 24)?你在这里读到的任何东西都是不可靠的。我看到 Fragment.onDestroy() 间歇性被调用,并且片段中的字段相应无效,据说受 setRetainInstance(true) 保护

W
Willi Mentzel

首先,查看关于保留片段的my post。它可能会有所帮助。

现在回答你的问题:

片段是否还保留其视图状态,或者会在配置更改时重新创建 - 究竟什么是“保留”?

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

当用户离开activity时,fragment会被销毁吗?

就像Activity一样,Fragment可能会在内存资源不足时被系统销毁。您是否让片段在配置更改时保留其实例状态不会影响系统是否会在您离开 Activity 后销毁 Fragment。如果您离开 Activity(即按主页按钮),Fragment 可能会或可能不会被破坏。如果您通过按后退按钮离开 Activity(因此,调用 finish() 并有效地销毁 Activity),所有附加的 ActivityFragment 也将被销毁。

为什么它不适用于后堆栈上的片段?

不支持它可能有多种原因,但对我来说最明显的原因是 Activity 持有对 FragmentManager 的引用,而 FragmentManager 管理后台堆栈。也就是说,无论您是否选择保留 FragmentActivity(以及 FragmentManager 的后台堆栈)都会在配置更改时被销毁。它可能不起作用的另一个原因是,如果允许保留片段 非保留片段都存在于同一个 backstack 上,事情可能会变得棘手。

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

保留的片段对于跨活动实例传播状态信息(尤其是线程管理)非常有用。例如,片段可以作为 ThreadAsyncTask 实例的宿主,管理其操作。有关详细信息,请参阅有关此主题的 my blog post

一般来说,我会将它与将 onConfigurationChangedActivity 一起使用...不要仅仅因为您太懒而无法正确实施/处理方向更改而将其用作创可贴。仅在需要时使用它。


视图对象不会被保留,它们总是在配置更改时被销毁。
据我所知,如果您有 setRetainInstance(true),则 Fragment java 对象及其所有内容在旋转时被破坏,但视图被重新创建.即再次调用 onCreatedView()。从 Android 1.0 开始,它基本上应该与 Activities 一起使用。我不认为使用它是“懒惰的”,或者使用它是不“正确的”。事实上,我不明白为什么它不是默认设置,或者你为什么想要关闭它。
我找到了您对“为什么它不适用于后堆栈上的片段?”的解释。难以理解。但也许我很笨:(
@dierre 可以通过多种方式销毁活动。例如,如果单击“返回”,则该活动将被销毁。如果单击“主页”,则活动将停止,并且在将来的某个时间内存不足时可能会被破坏。保留的 Fragment 仅在配置更改时保留,其中基础活动将被销毁并立即重新创建。在活动被销毁的所有其他情况下,保留的片段也将被销毁。
@AlexLockwood 您能否确认以下内容:即使使用了 setRetainInstance(true),仍然必须实现自己的持久性(savedInstanceState 或其他)才能处理所有场景:例如“home键,旋转,返回应用程序”使用构造函数调用重新创建我的片段,丢失所有状态变量。我有一个 AsyncTask 作为成员变量,这就是我想保留的原因,现在,如果我想让它工作,我不得不停止任务,保存状态,并在用户回来时恢复。所以总而言之,这只是帮助旋转的一种快速方法,但一般来说没有用。
s
suitianshi

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

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


您是否创建“仅数据”片段(没有任何小部件)作为位图的持有者,或者这些片段也可以具有小部件?当片段包含与上下文/活动相关的内容时,我已经阅读了一些关于产生内存泄漏的危险......
框架将为您清除 mActivity 引用。但我不知道在这种情况下运行时是否也会清除片段实例中的小部件。请尝试一下或深入研究源代码。
什么时候可以使用 setRetaininstance 的好例子
K
Kejun Xia

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

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


旋转屏幕时,我肯定会在保留的片段上再次调用 onCreateView。
这个链接是你自己的博客吗?如果是这种情况,你应该说清楚。
G
Gastón Saillén

setRetainInstance() - 已弃用

作为片段 Version 1.3.0-alpha01

片段上的 setRetainInstance() 方法已被弃用。随着 ViewModel 的引入,开发人员可以使用特定的 API 来保留可以与活动、片段和导航图相关联的状态。这允许开发人员使用正常的、未保留的 Fragment 并将他们想要保留的特定状态分开,避免常见的泄漏源,同时保持保留状态的单个创建和销毁的有用属性(即 ViewModel 的构造函数以及它收到的 onCleared() 回调)。


M
Marian Paździoch

setRetainInstance(boolean) 在您希望拥有一些不与 Activity 生命周期相关的组件时很有用。例如,rxloader 使用这种技术来“为 rxjava 的 Observable 处理 Android 的活动生命周期”(我发现 here)。