Android Reorder Fragment Backstack
Posted
技术标签:
【中文标题】Android Reorder Fragment Backstack【英文标题】: 【发布时间】:2014-03-07 02:01:12 【问题描述】:我的导航抽屉中列出了许多页面/片段,用户可能会经常在这些页面/片段之间切换,我希望它们在后台堆栈中以便他们可以导航回来,但我只想要每个片段的一个实例后台堆栈,这样用户就不必疯狂地按回很多次来退出应用程序。我不知道如何在不删除页面的情况下有效地“重新排序”backstack。
目前,当我更改页面时,我正在使用此代码更改片段并确保它仅在后堆栈中一次
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 '现在已经意识到 remove 不会影响 backstack,所以无需指出这一点):
[E]
[D] [D]
[C] [C] [C] [C]
[B] [B] [B] [B] [B]
[A] -> [A] -> [A] -> [A] -> [A] -> [A]
如果我在添加到后台堆栈时不使用名称而是使用 null,我会得到以下信息:
[C]
[E] [E]
[D] [D] [D]
[C] [C] [C] [C]
[B] [B] [B] [B] [B]
[A] -> [A] -> [A] -> [A] -> [A] -> [A]
我怎样才能得到我期望的行为?是否有可能,还是我需要自己记录更改并完全跳过后台堆栈?
【问题讨论】:
我正在尝试找到一种有效的方法来解决这个问题,我在我的问题上付出了一些努力 - 如果投票的人有勇气说出原因,那就太好了 抱歉,FragmentManager
API 中没有用于从后台堆栈中间移除Fragment
状态的方法。 API 仅公开了用于推送和弹出的标准堆栈机制。
我认为可能是这样。但我的用例似乎是一个非常有效、相当普遍的需求,您可以通过活动实现类似的需求。我希望有人可能知道帮助类或实现此目的的东西
好吧,我不知道任何现有的解决方案,也不能不使用反射或自定义FragmentManager
实现来实现。如果您愿意这样做,那么它实际上应该很容易实现。
我想应该可以手动创建您自己的自定义Fragment
回栈,使用您需要的任何功能。您将无法使用 BackStackRecord
类,因为它取决于堆栈模型;它必须是一个定制的解决方案。如果您有兴趣,那么我可能会在几天内有时间(或者其他人可以)写一个基于此的答案。或者,如果您愿意,您也可以自己尝试——应该不会太难。
【参考方案1】:
没有 API 可以做到这一点,但因为上周我也在想同样的事情, 我把它当作一个练习,我自己实现了它。
我的方法允许您从后台堆栈中的任何位置删除Fragment
,这是通过使用反射来修改将后台堆栈信息存储在FragmentManagerImpl 和BackStackRecord 中的内部变量来实现的。
有几个重要的变量:
mBackStack
- 存储包含Fragment
信息的BackStackRecord
s、以前的信息、动画等
mActive
- 全部添加 Fragment
s
mAvailBackStackIndices
- 存储新插入的记录可以使用的索引,即null
值的索引mActive
和其他
用 150+ Fragment
s 进行测试,没有发现任何泄漏,但只监视了 DDMS
中的堆,没有执行任何其他内存分析。
因此,由于某些内容可能被破坏,请探索代码,重新测试它,看看是否有人提供了更好的答案,然后重新考虑您是否真的需要在您的项目中这样做。
我以gist on GitHub 的形式上传了代码,希望对您有所帮助。
【讨论】:
一个有趣的方法,谢谢。需要大量代码才能使其工作,我将在本周晚些时候有更多时间时深入研究一下 正如我之前所说,我喜欢的代码有点太多了,但是,我相信这对于某些访问者来说是正确的解决方案,并且您需要付出一些努力,所以我会把赏金奖励给你!【参考方案2】:当您想重用之前的片段时,只需先隐藏所有片段并一次显示所需的片段即可。通过这样做,您可以重用您的片段,而无需删除它们,也无需重新加载片段。但请确保在实现之前您必须将片段添加到 backstack。
【讨论】:
如果你有 2000 个片段,你最终会 OOM。以上是关于Android Reorder Fragment Backstack的主要内容,如果未能解决你的问题,请参考以下文章