Android Reorder Fragment Backstack

时间:2014-02-09 21:33:43

标签: android android-fragments back-stack

我的导航抽屉中列出了许多页面/片段,用户可能经常在这些页面/片段之间进行切换,我希望它们在后台堆栈中以便他们可以导航回来,但我只想要每个片段的一个实例后台堆栈,这样用户就不必再按回疯狂的次数来退出应用程序。我无法弄清楚如何在没有删除页面的情况下有效地“重新排序”后台堆。

目前,当我更改页面时,我正在使用此代码更改片段,并确保它只在后面的堆栈中一次

  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] 

我怎样才能得到我期望的行为?它是否可能,或者我是否需要自己记录更改并完全跳过后端堆栈?

2 个答案:

答案 0 :(得分:21)

没有API可以做到这一点,但是因为我上周想知道同样的事情,
我把它当作一项练习,并自己实施。

我的方法允许您从Backstack中的任何位置删除Fragment,这可以通过使用refrection来修改存储FragmentManagerImplBackStackRecord中的Backstack信息的内部变量来实现。

几个重要变量:

  • mBackStack - 存储包含BackStackRecord信息的Fragment,以前的信息,动画等
  • mActive - 全部添加Fragment s
  • mAvailBackStackIndices - 存储新插入记录可以使用的索引,即null
  • mActive值的索引
  • 和其他

使用150 + Fragment进行测试,但未发现任何泄漏,但仅监视DDMS中的堆并且未执行任何其他内存分析。
因此,可能会破坏某些内容,探索代码,重新测试代码,看看是否有人提供了更好的答案,并重新考虑是否真的需要在项目中执行此操作。

我将代码上传为gist on GitHub,希望有所帮助。

答案 1 :(得分:0)

如果要在其之前重用片段,只需先隐藏所有片段并一次显示所需的片段。通过这样做,您可以重用您的片段而无需删除它们,也无需重新加载片段。但是在实现之前一定要确保将片段添加到backstack中。