FragmentTransaction:replace和addToBackStack不能同时使用,该怎么办?

10

我对Android开发还比较新,现在遇到了一些奇怪的问题。

  • 我有一个空的FrameLayout作为碎片的容器。
  • 如果用户第一次按按钮,就生成新的碎片并放置在容器中。
  • 如果用户后来再次按按钮,并且容器内已经存在碎片,则用新生成的碎片替换现有的碎片。
  • 如果用户按返回按钮,则弹出容器内的碎片。

这是我的代码:

public void showFragment(View v) {
    FragmentA f = new FragmentA();

    FragmentManager fm = getSupportFragmentManager();
    String tag = f.getFragmentTag(); // instance method of a to get a tag

    FragmentTransaction ft = fm.beginTransaction();
    ft.setCustomAnimations(R.anim.slide_in_top, 0, 0, R.anim.slide_out_top);            
    ft.replace(R.id.container, f, tag);
    ft.addToBackStack(tag);
    ft.commit();
}

@Override
public void onBackPressed() {
    FragmentManager fm = getSupportFragmentManager();
    if (fm.getBackStackEntryCount() > 0) {
        fm.popBackStack();
    } else {
        super.onBackPressed();
    }
}
当用户第一次按下按钮时,它的行为符合我的期望,将新片段添加到容器中。但是,当容器仍然包含一个片段时,用户第二次按下按钮时,它不是替换,而是在现有片段之上添加新的片段。因此,容器中有2个片段,需要按2次返回键才能删除所有片段。

我发现如果我删除这行代码

ft.addToBackStack();

将onBackPress()方法重新处理如下,它会像我预期的那样再次工作(每次在容器中只有1个片段)

基本上是手动删除片段,而不是使用popFromBackStack方法

private FragmentA currentFragment = null; // to hold the reference to exising fragment, if any.

@Override
public void onBackPressed() {
    if (currentFragment != null) {
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        ft.setCustomAnimations(0, R.anim.slide_out_top);
        ft.remove(currentFragment);
        ft.commit();

        currentFragment = null;
    } else {
        super.onBackPressed();
    }
}

所以,我的问题是:

  • replace和addToBackStack不可以一起使用吗?
  • 还是说我做错了什么?

非常感谢所有的评论和建议。


我认为这是原因:如果您在执行删除片段的事务时不调用addToBackStack(),则该片段将在提交事务时被销毁,用户无法返回。而如果您在删除片段时调用addToBackStack(),则该片段会停止并在用户导航回来时恢复。当您使用addToBackStack()时,先前的片段会停止并保留。请参阅:https://developer.android.com/guide/components/fragments.html#Transactions - Roger Huang
2个回答

13

addToBackstack会创建一个你的片段状态的快照。这意味着当你按下返回按钮时,实际上是回到了最后一次调用addToBackstack的状态。

在你的情况下,你添加了一个片段。按下返回键将删除此添加的片段。当你调用replace并再次添加到backstack时,你现在拥有backstack上的两个状态(1. 当你添加第一个片段时,2. 当你没有添加任何片段时)。如果你想要移除当前片段,请不要使用addToBackstack。只有在想要保留视图中片段状态时才使用addToBackstack。


嗨 Spidy,谢谢你的评论。我仍然很困惑,但是我可以说,在我的情况下,我不应该使用 addToBackStack 吗? - Tar_Tw45
1
是的,听起来您的用例不需要addToBackstack。 - Spidy
3
@Spidy 在 Android 开发者网站上提到,当在不同 Fragment 之间导航时,应使用 addToBackStack 提供正确的返回导航。您反对使用它们的理由是什么? 答:没有反对使用 addToBackStack。 另外,他所谓的“添加 Fragment”可能指的是通过 replace() 方法替换当前 Fragment 的情况,这也会放入返回堆栈中。 - Rule

-2

对于那些仍在寻找解决方案的人。

在主 Activity 类(托管片段)中,只需覆盖 onBackPressed() 方法即可。

@Override
public void onBackPressed() {
    if (getFragmentManager().getBackStackEntryCount() > 0 ){
        getFragmentManager().popBackStack();
    } else {
        super.onBackPressed();
    }
}

在Fragment中没有onBackPressed()方法,这个方法仅适用于activity。所以,当我们按下返回键时,默认情况下会显示activity的行为。

如果有前一个Activity,则会跳转到前一个Activity;否则应用程序将退出。

现在,我们需要重写此方法,告诉activity,当我们按下返回键时,如果后退堆栈中有任何片段,请弹出它们(这就是addToBackStack()派上用场的时候)。否则遵循默认行为。 here">在此处查找更多详细信息。

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