保留片段实例但不重新附加子片段

nPn*_*nPn 6 android android-fragments kotlin

更新:通过解决方案接受解释(错误)的答案点,但也可以看到我的基于Kotlin的解决方案作为下面的答案.

这段代码在Kotlin中,但我认为它是一个基本的android片段生命周期问题.

我有一个片段,其中包含对其他"subfragment"的引用

这基本上就是我在做什么:

  1. 我有一个retainInstance设置为true 的主片段
  2. 我在主片段中有一个字段,它将保存对子片段的引用,最初该字段为空
  3. 在主片段中onCreateView,我检查subfragment字段是否为null,如果是,我创建subFragment的实例并将其分配给字段
  4. 最后,我将subfragment添加到主片段布局中的容器中.
  5. 如果该字段不为null,即由于配置更改我们在onCreateView中,我不会重新创建子片段,我只是尝试将其添加到containter.

当设备旋转时,我确实观察了被调用的子片段onPaused()onDestroyView()方法,但是我没有看到在将子片段的保留引用添加到子片段的过程中在子片段上调用任何生命周期方法,当主片段添加到child_container时片段视图被重新创建.

净影响是我没有在主片段中看到子片段视图.如果我注释掉if(subfragment == null)并且每次只创建一个新的子片段,我确实在视图中看到了子片段.

更新

下面的答案确实指出了一个错误,其中childFragmentManager在配置更改时不会保留.这最终将破坏我的预期用途,即在旋转后保留背板,但我认为我看到的是不同的东西.

我在活动onWindowFocusChanged方法中添加了代码,在首次启动应用程序时,我看到类似的内容:

activity is in view
fm = FragmentManager{b13b9b18 in Tab1Fragment{b13b2b98}}
tab 1 fragments = [DefaultSubfragment{b13bb610 #0 id=0x7f0c0078}]
Run Code Online (Sandbox Code Playgroud)

然后轮换后:

activity is in view
fm = FragmentManager{b13f9c30 in Tab1Fragment{b13b2b98}}
tab 1 fragments = null
Run Code Online (Sandbox Code Playgroud)

这里的fm是childFragmentManager,正如你所看到的,我们仍然有相同的Tab1Fragment实例,但它有一个新的childFragmentManager,我认为这是不需要的,并且由于下面的答案中报告了错误.问题是我确实将子碎片添加到这个新的 childFragmentManger中.所以看起来事务永远不会执行对保留的片段的引用,但是如果我创建一个全新的片段就完成了.(我确实试过调用executePendingTransactions新的childFragmentManager)


class Tab1Fragment: Fragment() {

    var subfragment: DefaultSubfragment? = null

    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
                          savedInstanceState: Bundle?): View? {
        val rootView = inflater!!.inflate(R.layout.fragment_main, container, false)
        if (subfragment == null ) {
            subfragment = DefaultSubfragment()
            subfragment!!.sectionLabel = "label 1"
            subfragment!!.buttonText = "button 1"
        }
        addRootContentToContainer(R.id.child_container, content = subfragment!!)

    return rootView
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        retainInstance = true
    }

inline fun Fragment.addRootContentToContainer(containerId: Int, content: Fragment) {
    val transaction = childFragmentManager.beginTransaction()
    transaction.replace(containerId, content)
    transaction.commit()
}
Run Code Online (Sandbox Code Playgroud)

mar*_*inj 3

您的问题看起来与此处描述的问题类似:

https://code.google.com/p/android/issues/detail?id=74222

不幸的是这个问题可能不会被谷歌解决。

对 UI 或嵌套片段使用保留片段并不是一个好主意 - 建议使用它们来代替 onRetainNonConfigurationInstance,因此即。对于大型集合/数据结构。此外,您还可以发现加载器比保留的片段更好,它们在配置更改期间也会保留。

顺便提一句。我发现保留的片段更像是一种黑客行为 - 就像用来android:configChanges“修复”由屏幕旋转引起的问题。这一切都会起作用,直到用户按下主屏幕并且 Android 决定终止您的应用程序进程。一旦用户想要返回您的应用程序 - 您保留的片段将被销毁 - 您仍然需要重新创建它。因此,最好对所有内容进行编码,就像您的资源随时可能被破坏一样。