PopBackStack 但将第一个片段保留在 android
Posted
技术标签:
【中文标题】PopBackStack 但将第一个片段保留在 android【英文标题】:PopBackStack but keep the first fragment in android 【发布时间】:2015-04-06 07:24:24 【问题描述】:我在做fragment transaction,backstack是这样的:
fragA => fragB => fragC => fragD
从fragD回来后我想回到fragA
fragD => onBackPress => fragA
所以,我尝试了如下代码:
getChildFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
但它清除了所有的 backstack ,我怎样才能将第一个片段保留在 backstack 中?非常感谢
【问题讨论】:
这个答案在这里:- ***.com/a/28115271/9969285 是最简单和最好的解决方法!在我的情况下,它适用于多个片段(可以在第一个片段之后以任何顺序启动),并且后按将始终返回到第一个创建的片段。非常重要的一点要记住,不要在创建第一个片段时添加到 backstack,而是在添加所有其他片段时添加到 backstack。 【参考方案1】:例如您可以执行以下操作:
添加 fragA 而不将其添加到 backStack。所以它总是在 活动,并且不会对后退按钮做出反应。 当你打开 fragD 时,你应该clear fragment BackStack。所以当你按下 D 片段的返回按钮时,你会回到 A。附:还有其他方法可以做你想做的事。这取决于...
【讨论】:
我清除了整个后台堆栈,然后添加回 fragA 和 fragD 。谢谢 很多人都会犯这个错误,请记住您正在将事务添加到后台堆栈中,因此通常不应将添加流中第一个片段的事务添加到后台堆栈中(您为什么要想回到空状态?)【参考方案2】:因为“后退堆栈”具有类似堆栈的行为...后进先出...您添加到后退堆栈的最后一个片段将首先从后退堆栈中弹出。您将需要通过指定您自己的来手动实现所需的行为。使用FragmentManager
类方法并不难。
如果您在将片段添加到事务时“标记”它们...
fragmentTransaction.add(new FragmentA(), "FragmentA_Tag");
您可以稍后确定在按下返回按钮时显示哪个片段...
FragmentA f = fragmentManager.findFragmentByTag("FragmentA_Tag");
if(f != null)
f.show();
您如何确定显示哪个片段完全取决于您。您可以跟踪当前可见的片段,也可以使用Fragment
类的isHidden
方法...顺便说一句,我这里说的是原生片段,不支持库的片段。
【讨论】:
【参考方案3】:backstack 包含有关事务的记录,而不是片段本身。
所以你不应该将第一笔交易的记录(null -> fragA)添加到backstack。
并且所有其他交易的记录都应该添加到 backstack 中。
在这种情况下,您 preformpopBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
android 删除了除 fragA 之外的所有片段,因为没有任何关于如何添加 fragA 的记录。
【讨论】:
【参考方案4】:就在几天前,我开始学习 Android 中的 Fragment。我也遇到了这个问题。在这里,我展示了我的解决方案以及我如何解决这个问题。如果我的代码不正确,请修复。这个时候我们有什么?活动,许多片段和他们的后台。我们希望从 Drawer 菜单中打开每个片段,并从 backstack 中清除所有其他片段。但是,我们必须只持有一个 Home 片段。当我们停留在主页片段并且用户按下返回按钮时,应用程序正在关闭。
Activity.class
protected void onCreate(Bundle savedInstanceState)
...
// adding Home fragment without adding transaction into backstack
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.container, HomeFragment.newInstance("args"), null);
ft.commit();
@Override
public void onBackPressed()
if (getSupportFragmentManager().getBackStackEntryCount() == 0)
finish();
public void addFragmentFromMenu(Fragment fragment)
String backStateName = fragment.getClass().getName();
clearBackStack();
FragmentManager manager = getSupportFragmentManager();
if(manager.getBackStackEntryCount()> 0)
boolean fragmentPopped = manager.popBackStackImmediate(backStateName, 0);
if (!fragmentPopped && manager.findFragmentByTag(backStateName) == null)
//fragment not in back stack, create it.
addFragment(fragment, manager, backStateName);
else // no fragments
addFragment(fragment, manager, backStateName);
public void addFragment(Fragment fragment, FragmentManager manager, String backStateName)
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.container, fragment, backStateName);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(backStateName);
ft.commit();
public void clearBackStack()
getSupportFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
然后点击抽屉菜单项
@Override
public boolean onNavigationItemSelected(MenuItem item)
int id = item.getItemId();
if (id == R.id.nav_camera)
addFragmentFromMenu(CameraFragment.newInstance("cam1", "cam2"));
else if (id == R.id.nav_gallery)
addFragmentFromMenu(TestFragment.newInstance("test1","test2"));
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
【讨论】:
【参考方案5】:看了很多帖子,我是这样想的:
在 fragC => fragD 方法中,做两个事务:
1 清除回栈,fragC => fragA
2 fragA => fragD
但是这样一来,fragA原来的状态就有可能被破坏了。
public static void changeFragCtoD(FragmentManager fm, Fragment fragD)
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction
.replace(R.id.containerViewId, new fragAClass())
.commit();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction
.replace(R.id.containerViewId, fragD)
.addToBackStack(fragD.getClass().getName())
.commit();
现在按下 fragD 会返回 fragA。
【讨论】:
【参考方案6】:我已经完成了以下方式。清除所有片段然后添加第一个家庭片段
FragmentManager fm = getActivity().getSupportFragmentManager();
fm.popBackStack(Constants.TAG_HOME, FragmentManager.POP_BACK_STACK_INCLUSIVE);
((MainActivity) activity).manageFragment(new HomeFragment(), Constants.TAG_HOME);
// write down below function in main activity
public void manageFragment(Fragment fragment, String tag)
FragmentManager fragmentManager = getSupportFragmentManager();
if (!fragmentManager.popBackStackImmediate(tag, 0))
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.add(R.id.content_frame, fragment, tag);
ft.addToBackStack(tag);
ft.commit();
【讨论】:
【参考方案7】:1) 使用以下代码添加第一个片段
android.support.v4.app.FragmentManager fm = getActivity().getSupportFragmentManager();
android.support.v4.app.FragmentTransaction ft=fm.beginTransaction();
if (fm.findFragmentById(R.id.fragment_container) != null)
ft.hide(fm.findFragmentById(R.id.fragment_container));
ft.add(R.id.fragment_container, new OneFragment(),OneFragment.class.getCanonicalName())
.addToBackStack(OneFragment.class.getCanonicalName()).commit();
2) 使用以下代码从第一个片段添加第二个片段
android.support.v4.app.FragmentManager fm = getActivity().getSupportFragmentManager();
android.support.v4.app.FragmentTransaction ft=fm.beginTransaction();
if (fm.findFragmentById(R.id.fragment_container) != null)
ft.hide(fm.findFragmentById(R.id.fragment_container));
ft.add(R.id.fragment_container,new TwoFragment(),TwoFragment.class.getCanonicalName())
.addToBackStack(TwoFragment.class.getCanonicalName()).commit();
3) 使用以下代码从第二个片段添加第三个片段
android.support.v4.app.FragmentManager fm = getActivity().getSupportFragmentManager();
android.support.v4.app.FragmentTransaction ft=fm.beginTransaction();
if (fm.findFragmentById(R.id.fragment_container) != null)
ft.hide(fm.findFragmentById(R.id.fragment_container));
ft.add(R.id.fragment_container, new ThreeFragment(),ThreeFragment.class.getCanonicalName())
.addToBackStack(ThreeFragment.class.getCanonicalName()).commit();
4) 使用以下代码从第三个片段添加第四个片段
android.support.v4.app.FragmentManager fm = getActivity().getSupportFragmentManager();
android.support.v4.app.FragmentTransaction ft=fm.beginTransaction();
if (fm.findFragmentById(R.id.fragment_container) != null)
ft.hide(fm.findFragmentById(R.id.fragment_container));
ft.add(R.id.fragment_container, new FourFragment(),ThreeFragment.class.getCanonicalName())
.addToBackStack(FourFragment.class.getCanonicalName()).commit();
5) onBackPressed() 请写下代码
@Override
public void onBackPressed()
hideKeyboard(MainActivity.this);
Fragment currentFragment = this.getSupportFragmentManager().findFragmentById(R.id.fragment_container);
if (currentFragment.getClass().getName().equalsIgnoreCase(FourFragment.class.getName())) // Using this code come from third fragment to first fragment
Fragment f = this.getSupportFragmentManager().findFragmentByTag(TwoFragment.class.getCanonicalName());
if (f != null)
this.getSupportFragmentManager().popBackStackImmediate(f.getClass().getCanonicalName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
else
super.onBackPressed();
【讨论】:
【参考方案8】:记住我的话,完整的FragmentTransaction
s 被添加到 backstack 而不仅仅是一个片段,这意味着即使您在单个事务中添加和删除片段,调用poBackStack()
也会反转完整的事务。在其参数中传递一个标签会弹出所有事务直到标记的事务,甚至弹出标记的事务(以防FragmentManager.POP_BACK_STACK_INCLUSIVE
添加到参数中)
因此,更多的是关于如何添加它而不是如何删除它。
见Performing Fragment Transactions
【讨论】:
【参考方案9】:我知道现在回答您的问题为时已晚,但这可能对其他人有所帮助。 由于我这几天一直在寻找解决方案...我已经使用 for 循环解决了它,我认为这是最简单的方法。
首先,这样初始化一个整数
int count = getSupportFragmentManager().getBackStackEntryCount();
其中 getBackStackEntryCount() 将计算事务数。
然后在你的 fragD 中调用 FragmentTransaction 方法之前添加这个 for 循环
for (int i = 0; i < count; i++)
getSupportFragmentManager().popBackStack();
for 循环会为您解决问题,popBackStack() 会将您返回到 fragA
看起来像这样
int count = getSupportFragmentManager().getBackStackEntryCount();
for (int i = 0; i < count; i++)
getSupportFragmentManager().popBackStack();
fragmentTransaction.replace(R.id.frame_layout, new FoodFragment(), "Food").addToBackStack(null);
fragmentTransaction.commit();
【讨论】:
【参考方案10】:您可以覆盖 onbackpressed (Mainactivity) 并使用片段管理器的 getBackStackEntryCount(),您可以检查它是否不等于 1,并且仅在该条件下 popbackstack。
@Override
public void onBackPressed()
if (getSupportFragmentManager().getBackStackEntryCount() > 0)
if (!(getSupportFragmentManager().getBackStackEntryCount() == 1))
getSupportFragmentManager().popBackStack() ;
【讨论】:
以上是关于PopBackStack 但将第一个片段保留在 android的主要内容,如果未能解决你的问题,请参考以下文章
在 PopBackStack 之后片段弹出调用 OnViewCreated
popBackStack导致一次又一次调用片段的oncreateView
如何知道何时调用了`navController.popBackStack()`?
BottomNavigation popBackStack() 导航到 startDestination 而不是上一个片段