以编程方式返回回退栈中的上一个片段

262

假设我有一个活动,其中的片段是以编程方式添加的:

private void animateToFragment(Fragment newFragment, String tag) {
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    ft.replace(R.id.fragment_container, newFragment, tag);
    ft.addToBackStack(null);
    ft.commit();
}

如何最好地返回到之前可见的片段?

我发现在 Android 上通过按钮点击触发后退功能,但我认为模拟后退键事件并不是正确的方式(而且我也无法让它起作用):

dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));

调用finish()只会关闭我不感兴趣的活动。

有更好的方法吗?

15个回答

405

105
getFragmentManager().popBackStackImmediate();解决了问题。谢谢。 - Aske B.
2
没有看到代码,很难说...但它应该放在代码部分中,当您想要“关闭”当前片段并返回上一个片段时执行。 - stuckless
2
getSupportFragmentManager()是什么意思? - ViliusK
1
@alicanbatur 是的,你需要使用addToBackStack()。 - Abhijit Chakra
6
别忘了在你的代码中加入 "addToBackStack("tag")"。 "fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();" 如果你写成 addToBackStack(null),系统会自动处理,但是如果你指定了一个标签,就需要手动处理。 - Khaled Saifullah
显示剩余9条评论

141

为了进一步说明其他已提供的答案,这是我的解决方案(放置在一个Activity中):

@Override
public void onBackPressed(){
    FragmentManager fm = getFragmentManager();
    if (fm.getBackStackEntryCount() > 0) {
        Log.i("MainActivity", "popping backstack");
        fm.popBackStack();
    } else {
        Log.i("MainActivity", "nothing on backstack, calling super");
        super.onBackPressed();  
    }
}

5
为什么会发生这种情况?在片段示例http://developer.android.com/training/basics/fragments/index.html中,它们没有覆盖onBackPressed事件,但是它们能够回退片段。我已经使用了trasaction.addToBackStack(null);但是没有任何反应。你能解释一下为什么吗? - Murtaza Khursheed Hussain
@MurtazaHussain 如果你想在这方面得到帮助,最好提出一个新问题。如果不看更多的代码,很难理解正在发生什么。 - Kyle Falconer
3
在我的情况下,我需要执行fm.getBackStackEntryCount() > 1才能在堆栈中只有第一个片段时调用活动。 - Facundo Olano
3
Android已经为您完成了这项工作:当在后退栈上有FragmentTransaction对象且用户按下返回按钮时,FragmentManager会从后退栈中弹出最近的事务并执行相反的操作(例如,如果该事务添加了一个片段,则移除它)。 - artkoenig

38

当我们更新/添加片段时,

应包括 .addToBackStack()

getSupportFragmentManager().beginTransaction()
    .add(detailFragment, "detail") // Add this transaction to the back stack (name is an optional name for this back stack state, or null).
    .addToBackStack(null)
    .commit();
如果我们在此之后调用getFragments.popBackStackImmediate(),则当我们添加/更新片段并返回到当前屏幕时,它将返回true。

27

Android导航架构组件。

以下代码在我的设备上正常工作:

findNavController().popBackStack()

当您使用自定义设计的工具栏时,此方法非常方便。运作得很好。 - karan_for_you
2
如果您正在使用navController,我认为您必须使用这种方法 - 我最初尝试了片段管理器(上面的答案),但后来尝试使用navController导航时崩溃了。 - Andy Weinstein

18

如果我在我的Fragment事务中没有添加addToBackStack(),那么这些答案将不起作用,但是,您可以使用:

如果我在我的Fragment事务中没有添加addToBackStack(),那么这些答案将不起作用,但是,您可以使用:

getActivity().onBackPressed();

从您的任何片段返回一步;


6
Kotlin翻译:requireActivity().onBackPressed()通俗易懂的翻译:在Kotlin中,“requireActivity().onBackPressed()”表示要求当前活动界面执行返回操作。 - Ayxan Haqverdili

10

在你的onBackPressed()方法中添加以下代码。如果你在返回堆栈中有任何片段,popBackStackImmediate()方法将使你回到上一个片段。

if(getFragmentManager().getBackStackEntryCount() > 0){
     getFragmentManager().popBackStackImmediate();
}
else{
    super.onBackPressed();
}

`


6
这个解决方案非常适用于基于底部栏的片段导航,当您想在主要片段中按下“返回”键时关闭应用程序。另一方面,当您打开在我的代码中定义为“DetailedPizza”的二级片段(片段中的片段)时,它将返回主要片段的先前状态。在活动中按下返回键时,请添加以下内容:
Fragment home = getSupportFragmentManager().findFragmentByTag("DetailedPizza");

if (home instanceof FragmentDetailedPizza && home.isVisible()) {
    if (getFragmentManager().getBackStackEntryCount() != 0) {
        getFragmentManager().popBackStack();
    } else {
        super.onBackPressed();
    }
} else {
    //Primary fragment
    moveTaskToBack(true);
}

这样可以启动另一个碎片:

Fragment someFragment = new FragmentDetailedPizza();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.container_body, someFragment, "DetailedPizza");
transaction.addToBackStack("DetailedPizza");
transaction.commit();

5

Kotlin 答案

  1. 首先,调用 FragmentManager
  2. 然后,使用 onBackPressed() 方法。

在 Android Studio 4.0 中使用 Kotlin 编码:

fragmentManager?.popBackStack()

也尝试使用 activity?.onBackPressed() - Daniel Cettour

2
要让该片段再次出现,只需将您希望在后退时返回的片段添加到后退栈中,例如:
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Fragment fragment = new LoginFragment();
        //replacing the fragment
        if (fragment != null) {
            FragmentTransaction ft = ((FragmentActivity)getContext()).getSupportFragmentManager().beginTransaction();
            ft.replace(R.id.content_frame, fragment);
            ft.addToBackStack("SignupFragment");
            ft.commit();
        }
    }
});

在上述情况下,当按下“Button button”时,我正在打开LoginFragment,此时用户处于SignupFragment中。因此,如果调用addToBackStack(TAG),其中TAG =“SignupFragment”,那么当在LoginFragment中按下返回按钮时,我们会回到SignUpFragment
祝编码愉快!

我认为,标签不会产生影响,甚至可能为空。 - CoolMind

2
使用以下代码以编程方式返回到上一个片段。
if ( getFragmentManager().getBackStackEntryCount() > 0) 
{
          getFragmentManager().popBackStack();
          return;
}
super.onBackPressed();

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