我的导航抽屉中列出了许多页面/片段,用户可能经常在这些页面/片段之间进行切换,我希望它们在后台堆栈中以便他们可以导航回来,但我只想要每个片段的一个实例后台堆栈,这样用户就不必再按回疯狂的次数来退出应用程序。我无法弄清楚如何在没有删除页面的情况下有效地“重新排序”后台堆。
目前,当我更改页面时,我正在使用此代码更改片段,并确保它只在后面的堆栈中一次
if (mFragMgr == null) {
mFragMgr = getSupportFragmentManager();
}
String backStateName = fragmentDescriptor.name();
boolean fragmentPopped = mFragMgr.popBackStackImmediate(backStateName, 0);
if (!fragmentPopped){
mFragMgr.beginTransaction()
.remove((Fragment) mFragment)
.replace(R.id.content_frame, (Fragment) mFragment)
.addToBackStack(backStateName)
.commit();
}
我在onBackPressed中使用此代码
@Override
public void onBackPressed() {
if (mFragMgr.getBackStackEntryCount() > 0) {
mFragMgr.popBackStackImmediate();
} else {
super.onBackPressed();
}
}
这有效,但这意味着它会删除我不想删除的页面。例如:
当我的用户按照A > B > C > D > E > C
的顺序访问6个页面时,因为我正在执行删除操作,我预计会有以下堆栈:
[E] [C]
[D] [D] [E]
[C] [C] [C] [D]
[B] [B] [B] [B] [B]
[A] -> [A] -> [A] -> [A] -> [A] -> [A]
但实际得到的是以下内容 - 它将所有内容弹出到与名称匹配的元素,这与我是否包含“.remove((Fragment)mFragment)”无关 - ( I现在已经意识到删除不会影响backstack,所以不需要指出):
[E]
[D] [D]
[C] [C] [C] [C]
[B] [B] [B] [B] [B]
[A] -> [A] -> [A] -> [A] -> [A] -> [A]
如果我不使用名称,而是在添加到backstack时使用null,我会得到以下内容:
[C]
[E] [E]
[D] [D] [D]
[C] [C] [C] [C]
[B] [B] [B] [B] [B]
[A] -> [A] -> [A] -> [A] -> [A] -> [A]
我怎样才能得到我期望的行为?它是否可能,或者我是否需要自己记录更改并完全跳过后端堆栈?
答案 0 :(得分:21)
没有API可以做到这一点,但是因为我上周想知道同样的事情,
我把它当作一项练习,并自己实施。
我的方法允许您从Backstack中的任何位置删除Fragment
,这可以通过使用refrection来修改存储FragmentManagerImpl和BackStackRecord中的Backstack信息的内部变量来实现。
几个重要变量:
mBackStack
- 存储包含BackStackRecord
信息的Fragment
,以前的信息,动画等mActive
- 全部添加Fragment
s mAvailBackStackIndices
- 存储新插入记录可以使用的索引,即null
mActive
值的索引
使用150 + Fragment
进行测试,但未发现任何泄漏,但仅监视DDMS
中的堆并且未执行任何其他内存分析。
因此,可能会破坏某些内容,探索代码,重新测试代码,看看是否有人提供了更好的答案,并重新考虑是否真的需要在项目中执行此操作。
我将代码上传为gist on GitHub,希望有所帮助。
答案 1 :(得分:0)
如果要在其之前重用片段,只需先隐藏所有片段并一次显示所需的片段。通过这样做,您可以重用您的片段而无需删除它们,也无需重新加载片段。但是在实现之前一定要确保将片段添加到backstack中。