如何在安卓中从返回栈中删除特定的片段

26

我有一个关于从后台栈中删除特定片段的问题。我的场景如下:将Fragment-1替换为Fragment-2,然后将Fragment-2替换为Fragment-3。

调用顺序; Fragment-1 -> Fragment-2 -> Fragment-3。

当Fragment-3在屏幕上时,然后点击返回按钮,我想回到Fragment-1。这意味着我想从后台栈中删除Fragment-2。

如何做到这一点?


1
你可以轻松地切换 Fragment,而不是删除它。 - koutuk
5个回答

28

回退栈中不包含Fragment,而是FragmentTransaction。当你调用popBackStack()时,事务会被再次应用,但是是后向的。这意味着(假设每次都addToBackStackTrace(null)),在你的回退栈中有:

1->2
2->3

如果你不将第二个事务添加到后退栈中,结果就是你的后退栈只有

1->2

因此,按下返回按钮将导致执行2->1,由于片段2不存在(您现在在片段3上),因此会导致错误。
最简单的解决方案是在从2到3之前弹出后退栈

//from fragment-2:
getFragmentManager().popBackStack();
getFragmentManager().beginTransaction()
   .replace(R.id.container, fragment3)
   .addToBackStack(null)
   .commit();

我在这里做的是这样的:从片段2返回到片段1,然后直接进入片段3。这样按下返回按钮将再次从3返回到1。


这不是我想要的确切解决方案。当进入Fragment-3时,我必须将Fragment-2添加到返回堆栈中。在Fragment-3中,根据条件,如果没有任何操作就要删除返回堆栈中的Fragment-2,然后单击返回按钮,只想回到Fragment-1。 - nihasmata
1
@sahin 好的,那这不是一个可行的选项...也许你可以尝试使用popBackStack (int id, int flags),但我没有尝试过,我不知道它在动画方面的行为如何... - Ilario
3
当你从2号Fragment转到3号Fragment之前弹出后退栈,系统会尝试显示1号Fragment。每次当你弹出第N个Fragment时,它会尝试显示第N-1个Fragment。如果你强制跳转到第3个Fragment,那么在第1个Fragment的onCreateView期间就会出现NullPointerException(空指针异常)错误。 - Yazon2006
@llario,感谢您的回答,解决了我的问题。 - Morton
1
@sunlover3 我在Lollipop上使用了这种方法,四年半后很多事情可能已经改变了...至少有一个关于这个问题的问题,https://dev59.com/jFMI5IYBdhLWcg3wS5rP 我不再从事安卓开发,无法再为您提供更多帮助,抱歉。 - Ilario
显示剩余2条评论

10

我有一个和你很类似的情况,我的解决方案是检查我拥有的backStack事务数量。如果事务数量大于0,那么我会立即弹出它,这样在按返回键时就会跳过它。

if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
        getSupportFragmentManager().popBackStackImmediate();
}
...
fragmentTransaction.replace(R.id.main_fragment, newFrag, MAIN_FRAGMENT_TAG);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
fragmentTransaction.commit();

这将成功执行:

  • A -> B(按下返回键)-> 返回到 A

  • A -> B -> C(按下返回键)-> 返回到 A

我唯一看到的不足之处是在进入片段C之前,会有一个快速的闪烁,显示了片段A。


像其他人建议的那样只调用.popStack() - 在我的情况下 - 导致视图在回到A之后自动恢复到C - 在按返回按钮之前。这里列出的popBackStackImmediate()是我情况下的关键所在,现在我可以从C返回到A的返回按钮了 - 我遇到的其他答案都没有提到它。谢谢! - Gene Bo
请指定在哪里编写此代码?我的意思是哪个片段。 - Sreekanth Karumanaghat

6

如果您在同一个活动中添加/启动了所有三个片段,而不是使用add(),请改用replace()(将Fragment2替换为Fragment3)。replace方法会在添加新的片段之前从后退栈中删除当前片段。如果您要从另一个活动启动Fragment3,因此无法使用replace(),请在启动新活动之前从后退栈中删除Fragment2(这将添加Fragment3):

// in Fragment2, before adding Fragment3:
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
               .remove(this) // "this" refers to current instance of Fragment2
               .commit();
fragmentManager.popBackStack();
// now go ahead and launch (add) fragment3
// if fragment3 is launched from a different activity, 
// start that activity instead
fragmentManager.beginTransaction()
               .add(R.id.a_container_view_in_activity, new Fragment3(),
                    Fargment3.FRAGMENT3_ID)
               .commit();

4

代码片段A -> 片段B

片段A添加到片段回退栈

FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_layout_container, new fragmentB());
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();

代码片段 B -> 代码片段 C

不要将 代码片段 B 添加到碎片的后退栈中。

FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_layout_container, new fragmentC());
fragmentTransaction.commit();

它将按照以下方式工作:A -> B -> C,并在返回时 C-> A,就像您期望的那样。

希望这能对您有所帮助。


如果你想再次使用B->A,就不能使用它。 - Stevie

3
   for (int i = 0; i < mFragmentManager.getBackStackEntryCount(); i++) {
        currentFragment = mFragmentManager.getFragments().get(i);
        if (!(currentFragment instanceof ParticularFragment))
            mFragmentManager.popBackStack();
        else
            break;
    }

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