【问题标题】:FragmentTransaction : replace and addToBackStack not working together?FragmentTransaction:replace 和 addToBackStack 不能一起工作?
【发布时间】:2014-01-07 12:40:06
【问题描述】:

我对 Android 开发还很陌生,现在遇到了奇怪的行为。

  • 我有一个空 FrameLayout 作为片段的容器。
  • 如果用户第一次按下按钮,则生成新的 Fragment 并放入容器中。
  • 如果用户稍后按下按钮并且容器内有现有片段,请将现有片段替换为新生成的片段。
  • 如果用户按下返回按钮,弹出容器内的片段。

这是我的代码

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 不能一起工作?
  • 或者,我做错了什么?

感谢所有 cmets 和建议。

【问题讨论】:

  • 我认为这就是原因:“如果您在执行删除片段的事务时不调用 addToBackStack() ,那么当提交事务并且用户无法返回时,该片段将被销毁然而,如果您在删除片段时确实调用了 addToBackStack(),那么片段将停止,并且如果用户导航回来,它将恢复。”当您使用 addToBackStack() 时,先前的片段将停止并保留。见:developer.android.com/guide/components/…

标签: android android-fragments fragmenttransaction


【解决方案1】:

addToBackstack 创建片段状态的快照。这意味着当您按下后退按钮时,您实际上是恢复到调用addToBackstack 的最后一个状态。

在您的情况下,您添加了一个片段。后退按钮将删除这个添加的片段。当您调用 replace 并再次添加到 backstack 时,您现在在 backstack 上有两种状态(1. 当您添加了第一个片段时,2. 当您没有添加片段时)。如果你用后退按钮移除当前片段,就不要使用 addToBackstack。仅当您想在视图中保留片段的状态时才使用 addToBackstack。

【讨论】:

  • 嗨 Spidy,感谢您的评论。我仍然很困惑,但我可以说,就我而言,我不应该使用 addToBackStack 吗?
  • 是的,听起来您的用例不需要 addToBackstack
  • @Spidy 在 Android 开发者网站developer.android.com/training/implementing-navigation/… 上他们说您应该使用 addToBackStack 在片段之间导航时提供正确的后退导航。你有什么理由不使用它们?和2:“在你的情况下,你添加一个片段。后退按钮将删除这个添加的片段。当你调用replace并再次添加到backstack时,你现在在backstack上有两个状态”。他在代码的什么地方添加了片段?我只看到 replace()
【解决方案2】:

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

在主要的Activity 类(托管片段)中,只需覆盖onBackPressed()

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

fragment中没有onBackPressed()方法,该方法只针对activity。所以,当我们按下返回键时,会显示activity的默认行为,即

你要么去以前的活动(如果有的话)要么去应用程序 将退出。

现在我们需要重写这个方法来告诉activity,当我们按下返回键时,如果返回堆栈中有任何片段,则将它们弹出(这就是addToBackStack() 出现的时候)。否则遵循默认行为。

在此处了解更多详情here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-28
    • 1970-01-01
    • 2019-08-17
    • 2016-11-23
    • 2019-02-18
    • 2015-05-16
    • 2017-10-14
    • 2012-06-01
    相关资源
    最近更新 更多