【问题标题】:How setRetainInstance(true) in Fragment know that it has to be retained?Fragment 中的 setRetainInstance(true) 如何知道它必须被保留?
【发布时间】:2021-12-08 20:15:45
【问题描述】:

我们在 Fragment 中有一个方法,用于在 Activity 被销毁并重新创建时,在方向改变的情况下保留 Fragment,

setRetainInstance(Boolean true/false)

如何区分 Activity 被重新创建(销毁并再次创建)和未完全销毁?

基本上,我想知道 Fragment 是如何知道何时必须完全销毁以及何时必须保留的。

【问题讨论】:

  • 我也看到了这篇文章。这不能回答我的问题。我的问题是关于内部运作和如何..
  • a) 你的问题不是很清楚。什么是“未完全摧毁”?您是什么意思片段“知道何时必须完全销毁”? b) Android 是开源的——任何关于“内部如何工作”的问题都可以通过自己阅读代码来回答。

标签: android android-fragments android-activity


【解决方案1】:

很简单:它没有。

保留的Fragments 被添加到FragmentManager 内的ViewModel。当Activity 被重新创建时,ViewModel 通过 Activity 的onRetainNonConfigurationInstance()/getLastNonConfigurationInstance() 机制在内部恢复(作为ComponentActivity 的一部分)。如果Activity 没有被重新创建,它和它的非配置实例就会消失,它们最终会被垃圾收集器清理掉。

【讨论】:

  • 但是,如果您不使用 ViewModel,Fragment 的 SetRetainInstance 仍然适用于 Activity。 ViewModel 在这里做什么? @Ryan M
  • @Gissipi_453 这只是内部实现。 Fragment 库是在 ViewModel 库之上实现的,因此它可以利用该功能,即使您自己没有明确使用 ViewModel
  • Android 上的 Fragment 已经存在很长时间了,ViewModel 只存在于最近 5 年。我认为我不同意这一点
  • @Gissipi_453 它已在 ViewModel 之上重写(由我在 Android Toolkit 团队的同事编写)。可以自己阅读the code进行验证(搜索FragmentManagerViewModel)。
  • 所有这一切,顺便说一句,假设你在谈论androidx Fragments。如果您使用的是 android.support 或框架 Fragments...好吧,您应该切换,因为它们有很多错误。
【解决方案2】:

Ryan 的回答为您提供了指导,但您必须阅读源代码


    /**
     * Control whether a fragment instance is retained across Activity
     * re-creation (such as from a configuration change). If set, the fragment
     * lifecycle will be slightly different when an activity is recreated:
     * <ul>
     * <li> {@link #onDestroy()} will not be called (but {@link #onDetach()} still
     * will be, because the fragment is being detached from its current activity).
     * <li> {@link #onCreate(Bundle)} will not be called since the fragment
     * is not being re-created.
     * <li> {@link #onAttach(Activity)} and {@link #onActivityCreated(Bundle)} <b>will</b>
     * still be called.
     * </ul>
     *
     * @param retain <code>true</code> to retain this fragment instance across configuration
     *               changes, <code>false</code> otherwise.
     *
     * @see #getRetainInstance()
     * @deprecated Instead of retaining the Fragment itself, use a non-retained Fragment and keep
     * retained state in a ViewModel attached to that Fragment. The ViewModel's constructor and
     * its onCleared() callback provide the signal for initial creation and final destruction of
     * the retained state.
     */
    @Deprecated
    public void setRetainInstance(boolean retain) {
        FragmentStrictMode.onSetRetainInstanceUsage(this);
        mRetainInstance = retain;
        if (mFragmentManager != null) {
            if (retain) {
                mFragmentManager.addRetainedFragment(this);
            } else {
                mFragmentManager.removeRetainedFragment(this);
            }
        } else {
            mRetainInstanceChangedWhileDetached = true;
        }
    }

(来源:cs.android.com

换句话说,FragmentManager 有一个保留片段列表。所以它知道必须保留哪些片段。

不用说,但使用 setRetainInstance(true) 已被弃用;最好将您尝试保留的任何 state 保存在 ViewModel 中,该 ViewModel 将在配置更改(以及其他内容)后继续存在,并在/如果重新创建片段时恢复状态。

关于“如果我不是,为什么要使用 ViewModel”:好吧,您可以使用 ViewModel,但框架本身不想传递这样的一个方便的机会来分离关注点:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-13
    • 2019-12-04
    • 2012-02-14
    • 1970-01-01
    • 1970-01-01
    • 2012-04-22
    • 2012-06-26
    • 2011-12-08
    相关资源
    最近更新 更多