FragmentTransaction::replace()的使用,是否需要加上addToBackStack()参数?

3

有一个流程来添加片段,然后稍后进行replace()操作。所有片段都是动态添加的,但并非所有片段调用了addToBackStack()

getSupportFragmentManager().beginTransaction()
    .add(R.id.frgment_holder, frgmtA, frgmtA.NAME)
    .commit();

在某些情况下,它可以添加另一个,例如:

getSupportFragmentManager().beginTransaction()
    .replace(R.id.frgment_holder, frgmtB)
    .addToBackStack(frgmtB.NAME)
    .commit();

使用带有frgmtB的replace()将从容器R.id.frgment_holder中删除frgmtA。 如果此时按下后退按钮,将弹出frgmtB。但是即使在添加时没有调用addToBackStack(),它是否会重新创建frgmtA?

如果在相同容器中使用一系列混合add()和replace()调用的流程中,有人调用了addToBackStack(),但有人没有调用,则后退按钮的行为会怎样?

编辑:

getSupportFragmentManager().beginTransaction()
        .replace(R.id.frgment_holder, frgmtB)
        .addToBackStack(frgmtB.NAME)
        .commit();

will the

getSupportFragmentManager().findFragmentByTag(frgmtA.NAME);

你还在寻找frgmtA吗?如果在添加frgmtA时也调用了addToBackStack()会发生什么呢?

文档中说:“首先搜索当前添加到管理器活动中的片段;如果没有找到这样的片段,则搜索所有当前在返回堆栈上的片段。”

情况如下:

  1. 添加frgmtA; 不调用add to stack; UI状态在此处改变;

(如果frgmtA不是通过add()动态添加的,而是在布局文件中指定为class="frgmtA"会怎样呢?)。

  1. 用frgmtB替换(); addToStack();

  2. 用frgmtC替换(); addToStack();

那么如果stackTop是frgmtC,则希望按下返回按钮时能够将第一个frgmtA和其最后的UI状态带回来。

3个回答

6

1.

.add(R.id.frgment_holder, frgmtA, frgmtA.NAME)
            .commit();
.replace(R.id.frgment_holder, frgmtB, frgmtB.NAME)
        .addToBackStack(frgmtB.NAME)
        .commit();`

替换操作会将holder中的frgmtA移除,并调用其onDestroyView方法(但由于它被引用于后退栈的事务数据中,所以frgmtA并不会被销毁)。然后frgmtB将被添加到holder中。 由于frgmtA并未被销毁,

标签应保留。
getSupportFragmentManager().findFragmentByTag(frgmtA.NAME); 

会找到它。

之后,点击返回按钮,它将从backStack中弹出顶部事务,然后反转事务。即从容器中删除frgmtB并将frgmtA重新添加回容器。由于没有对frgmtB的引用,因此调用了其onDestroy。

2.在

的情况下
add frgmtA;
replace() with frgmtB; addToStack();
replace() with frgmtC; addToStack(); 

如果想要通过返回按钮跳转到fragmentA,需要重写onBackPressed()方法,在其中执行以下操作:
popBackStack(frgmtB.NAME, POP_BACK_STACK_INCLUSIVE), 

该操作将在名为frgmtB.NAME的栈条目上方弹出事务,并对其执行反向事务,这将使frgmtA重新添加到容器中。


在我工作了大约4个小时后,你拯救了我的一天,谢谢(: - oguzhan

2

尝试把这一行代码根据你的需求进行调整

这是四行不同的代码,你可以检查一下。

getActivity().getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

getActivity().getSupportFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

    FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.framelayout, fragment);
    transaction.addToBackStack(null);

    getActivity().getSupportFragmentManager().popBackStack();

1

除非你使用onBackPressed()addOnBackStackChangedListener()干预返回按钮逻辑,否则一切都很简单明了

  • 如果通过addToBackStack()添加一个片段,则在点击返回时它将被删除
  • 如果回退栈中没有其他片段,则应用程序将关闭

谢谢Dimitar!但是仍然不清楚replace()将先前的片段从容器中删除意味着什么。如果之前的片段也被称为addToBackStack(),那么replace()的“removing”会摧毁先前的片段,还是将它们缓存在某个地方? - lannyf
replace()将删除容器中提供的id的任何现有片段。没有缓存。如果您想将replace()addToBackStack()结合使用,则会变得很重。您需要保留调用commit()时返回的正整数的引用。这将是您的后退堆栈ID。我建议远离复杂的情况,因为很容易失去理智:) 要么选择add()/remove()选定的片段,而不是用replace()轰炸它们,要么更改片段使用。 - Dimitar Genov
同意使用简单的添加/删除让操作系统处理推送/弹出。但是,如果需要覆盖用户管理的流程,“简单”的推送/弹出就无法帮助(这就是混淆的来源)。就像问题中所述的情况一样,有三个片段fA、fB、fC。fA可以通过add()添加或在xml的holder中定义为类;fB和fC稍后添加(可以使用add()或replace()完成)并添加到BackStack中。如果在fC上有一个按钮点击返回到fA,似乎没有办法(因为fA在holder中),除非弹出所有内容并创建一个新的fA从头开始添加。 - lannyf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接