即使调用了 disallowAddToBackStack,Fragment Transaction 也会添加到 backstack

Fragment Transaction is added to backstack even if disallowAddToBackStack is called

以下是回购此错误的示例代码:

如果我连续替换 3 个片段,并禁用第二个片段添加到后台堆栈。

        fragmentManager = supportFragmentManager
        val fargmentA = FragmentA()
        fragmentManager.beginTransaction().replace(R.id.container, fargmentA).addToBackStack("a").commitAllowingStateLoss();

        val fargmentB = FragmentB()
        fragmentManager.beginTransaction().replace(R.id.container, fargmentB).disallowAddToBackStack().commitAllowingStateLoss();
        
        val fargmentC = FargmentC()
        fragmentManager.beginTransaction().replace(R.id.container, fargmentC).addToBackStack("c").commitAllowingStateLoss();

在上面的交易之后,我调用了popBackStack():

  val count = fragmentManager.backStackEntryCount;
        for(i in 0 until count ){
            fragmentManager.popBackStackImmediate()
        }

我仍然可以看到从 FragmentB 调用了 onCreateView() 方法,我不允许将其添加到后台堆栈。

这是已知错误还是片段管理器的行为方式?

谢谢!

有两点要牢记:

  1. replace() 相当于在当前添加到该容器的每个片段上调用 ​​remove(),然后用新片段调用 add(),以便与 fragmentC 进行交易将删除 fragmentB 作为其操作的一部分
  2. popBackStack() 让您完全处于交易前的状态。这意味着 fragmentC 被删除(与 add() 相反)并添加 fragmentB(与 remove() 相反)

这意味着弹出您的 fragmentC 交易将带回 fragmentB - 您的 disallowAddToBackStack() 只是意味着您的 fragmentB 交易可以 从不被逆转。

当涉及到在同一个容器上混合 addToBackStack() 和非 addToBackStack() 片段事务时,这实际上有一些严重的影响:在您完成 fragmentB 事务之后,没有办法回到 fragmentA.

一般来说,这意味着如果那确实是您想要的,您可以将非后退堆栈 fragmentB 交易替换为

fragmentManager.popBackStack()
val fargmentB = FragmentB()
fragmentManager.beginTransaction().replace(R.id.container, fargmentB).addToBackStack("b").commitAllowingStateLoss();

这将确保所有交易都使用 addToBackStack() 并且逆转在每一步都按预期进行。

请注意,您的每笔交易都应根据 Fragment transaction guide 使用 setReorderingAllowed(true)。这将防止片段向上移动到更高生命周期级别然后立即向下移动的情况,并确保将 popBackStack()commit() 等组合操作一起 运行 作为单个原子转换。