我在管理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。
答案 0 :(得分:77)
replace()
做两件事:
这两个操作是保存为Backstack记录/事务的操作。请注意,片段A保持created
状态,并且其视图已被破坏。
现在popBackStack()
会撤消您添加到BackStack的上一笔交易。
在这种情况下,这将是两个步骤:
在此之后,片段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()
等其他方法移动代码。