Android FragmentTransaction:replace 和 addToBackStack 不一起工作?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20673333/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 03:14:14  来源:igfitidea点击:

FragmentTransaction : replace and addToBackStack not working together?

androidandroid-fragmentsfragmenttransaction

提问by Tar_Tw45

I'm fairly new to Android development and now running in to weird behaviour.

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

  • I have an empty FrameLayout to be the container of a fragment.
  • If user press a button for the first time, generate new Fragment and put inside container.
  • If user press a button later and there is existing fragment inside container, replace existing one with newly generated one.
  • If user press back button, pop away the fragment inside container.
  • 我有一个空的 FrameLayout 作为片段的容器。
  • 如果用户第一次按下按钮,则生成新的 Fragment 并放入容器中。
  • 如果用户稍后按下按钮并且容器内存在现有片段,则将现有片段替换为新生成的片段。
  • 如果用户按下后退按钮,弹出容器内的片段。

Here is my code

这是我的代码

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();
    }
}

When user press button for the first time, it behave like what I expected, add new fragment to container. But, the second time user press button while container still contains a fragment, instead of replacing, it add new one on top of existing one. So, 2 fragments inside container, 2 back press to remove all fragment.

当用户第一次按下按钮时,它的行为与我预期的一样,将新片段添加到容器中。但是,当容器仍然包含一个片段时,用户第二次按下按钮时,它不是替换,而是在现有片段之上添加新片段。因此,容器内有 2 个碎片,2 次后退以移除所有碎片。

I found that if I remove the line

我发现如果我删除该行

ft.addToBackStack();

And rework the onBackPress() method like following, it works again like I expected (1 fragment in container at a time)

并像下面那样重新编写 onBackPress() 方法,它再次像我预期的那样工作(一次容器中的 1 个片段)

basically, manually remove fragment instead of popFromBackStack method

基本上,手动删除片段而不是 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();
    }
}

So, my question are

所以,我的问题是

  • replace and addToBackStack is not working together?
  • or, did I do something wrong?
  • replace 和 addToBackStack 不能一起工作?
  • 或者,我做错了什么?

Appreciate all comments and suggestions.

感谢所有的意见和建议。

回答by Spidy

addToBackstackcreates a snapshot of your fragments state. Which means when you press the back button, you are actually reverting to the last state that addToBackstackwas called on.

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

In your case, you add a Fragment. The back button would remove this added fragment. When you call replace, and add to backstack again, you now have two states on the backstack (1. when you had the first fragment added, 2. when you had no fragments added). If you the back button to remove the current fragment, the don't use addToBackstack. Only use addToBackstack when you want to preserve the state of fragments in a view.

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

回答by KhogaEslam

For those, who are still looking for solution.

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

In the main Activityclass (which is hosting the fragments)just override onBackPressed().

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

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

There is no onBackPressed()method in fragment, and this method is just for the activity. So,when we press the back key, the default behaviour of activityis shown, which is

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

you will either go to previous activity(if there is any) or the app will exit.

您将转到上一个活动(如果有)或应用程序将退出。

Now we need to override this method to tell the activitythat when we press the back key, if there are any fragments in back stack, pop them out (and this is when the addToBackStack()comes into picture). Otherwise follow the default behaviour.

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

find more details here here

这里找到更多详细信息