popBackStack()和replace()操作有何不同?

时间:2013-07-22 17:00:19

标签: java android android-fragments

我在管理Fragments时在我的应用程序中遇到了一些奇怪的行为,我想知道是否可以帮助解释为什么会发生这种情况。

我有两个片段,我们将它们称为片段A和片段B.我的应用程序的一般流程是当用户以某种方式与片段A交互时,通过调用fragmentTransaction.replace()显示片段B(这种情况发生在所有情况下)。当我显示片段B时,我将片段A添加到后栈;然后,当用户按下片段B上的后退按钮时,片段A会通过从后面的堆栈中弹出来再次显示。

这一切都很好,但是今天我发现有一个来自Fragment B的流程调用fragmentTransaction.replace(),用当前在后栈上的Fragment A的相同实例替换Fragment B.

本身没有任何问题,但是当我从片段A回到片段B时会出现奇怪的行为。如果我调用fragmentTransaction.replace(),片段B的onCreate()方法不是调用。

但是,如果我从后堆栈中弹出Fragment A然后将其替换为Fragment B,则会触发Fragment B的onCreate()方法。这是为什么?

请注意,片段A和片段B的所有实例都是在其主机活动启动时创建的。

编辑以澄清。第二次调用onCreate()的情况如下:附加片段A =>用片段B替换,将片段A添加到后栈=>使用popBackStack() => pop片段A再次将片段A替换为片段B。

2 个答案:

答案 0 :(得分:77)

replace()做两件事:

  1. 从您指定的容器(C)中删除当前添加的片段(A)
  2. 将新片段(B)添加到同一容器
  3. 这两个操作是保存为Backstack记录/事务的操作。请注意,片段A保持created状态,并且其视图已被破坏。

    现在popBackStack()会撤消您添加到BackStack的上一笔交易。

    在这种情况下,这将是两个步骤:

    1. 从C
    2. 中删除B.
    3. 将A添加到C
    4. 在此之后,片段B变为detached,如果你没有保留对它的引用,它将被垃圾收集。

      要回答问题的第一部分,没有onCreate()来电,因为FragmentB仍处于created状态。回答问题的第二部分有点长。

      首先,了解您实际上并未向Backstack添加Fragments,添加FragmentTransactions非常重要。因此,当您认为“替换为片段B,将片段A添加到后台”时,您实际上将此整个操作添加到后台堆栈 - 即A的替换替换。此替换包含2操作 - 删除A并添加B.

      然后,下一步是弹出包含此替换的事务。所以你没有弹出FragmentA,你正在反转“删除A,添加B”,反之则是“删除B,添加A”。

      然后最后一步应该更清楚 - FragmentManager没有意识到B,所以当你在最后一步用A替换A来添加它时,B需要经历其早期生命周期方法 - onAttach()onCreate()

      下面的代码说明了正在发生的事情。

      FragmentManager fm  = getFragmentManager();
      FragmentA fragmentA = new FragmentA();
      FragmentB fragmentB = new FragmentB();
      
      // 1. Show A
      fm.beginTransaction()
        .add(fragmentA, R.id.container)
        .commit();
      
      // 2. Replace A with B
      // FragmentManager keeps reference to fragmentA;
      // it stays attached and created; fragmentB goes 
      // through lifecycle methods onAttach(), onCreate()
      // and so on.
      fm.beginTransaction()
        .replace(fragmentB, R.id.container)
        .addToBackstack(null)
        .commit();
      
      // 2'. Alternative to replace() method
      fm.beginTransaction()
        .remove(fragmentA)
        .add(fragmentB, R.id.container)
        .addToBackstack(null)
        .commit();
      
      // 3. Reverse (2); Result - A is visible
      // What happens:
      //   1) fragmentB is removed from container, it is detached now;
      //      FragmentManager doesn't keep reference to it anymore
      //   2) Instance of FragmentA is placed back in the container
      // Now your Backstack is empty, FragmentManager is aware only
      // of FragmentA instance
      fm.popBackStack();
      
      // 4. Show B
      // Since fragmentB was detached, it goes through its early
      // lifecycle methods: onAttach() and onCreate().
      fm.beginTransaction()
        .replace(fragmentB, R.id.container)
        .addToBackstack(null)
        .commit();
      

答案 1 :(得分:0)

这可能是因为片段管理器重用片段实例而是重新创建它。如果片段B onCreate()中的代码需要在显示片段时执行,则使用onResume()等其他方法移动代码。