简体   繁体   English

Android Reorder Fragment Backstack

[英]Android Reorder Fragment Backstack

I have a number of pages/fragments listed in my navigation drawer, the user is likely to switch between these frequently and I want them in the backstack so that they can navigate back, but I only want one instance of each fragment in the backstack so that the user doesn't not have to press back an insane number of times to exit the app. 我的导航抽屉中列出了许多页面/片段,用户可能经常在这些页面/片段之间切换,我希望它们可以在后台进行导航,以便他们可以导航回来,但我只想在后台堆栈中使用每个片段的一个实例用户不必按下疯狂的次数退出应用程序。 I can't figure out how to effectively 'reorder' the backstack' without pages getting removed. 我无法弄清楚如何在没有删除页面的情况下有效地“重新排序”后台堆栈。

Currently when I change page I was using this code to change the fragment and make sure it's only in the back stack once 目前,当我更改页面时,我正在使用此代码更改片段并确保它仅在后面的堆栈中一次

  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();
  }

I use this code in onBackPressed 我在onBackPressed中使用此代码

  @Override
  public void onBackPressed() {
      if (mFragMgr.getBackStackEntryCount() > 0) {
          mFragMgr.popBackStackImmediate();
      } else {
          super.onBackPressed();
      }
  }

This works but it means it removes pages I don't want removed. 这有效,但这意味着它删除了我不想删除的页面。 Example: 例:

When my user visits 6 pages in the order A > B > C > D > E > C because I'm doing a remove I expected the following stack: 当我的用户按照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]

But what I actually get is the following - it pops everything up to the element that matches the name, this is regardless of whether I include the ".remove((Fragment) mFragment)" or not - ( I've already realised now that remove isn't affecting the backstack, so no need to point that out ): 但实际得到的是以下内容 - 它会将所有内容弹出到与名称相匹配的元素,这与我是否包含“.remove((Fragment)mFragment)”无关 - ( 我已经意识到了remove不会影响backstack,所以不需要指出那个 ):

                            [E]
                     [D]    [D]
              [C]    [C]    [C]    [C]
       [B]    [B]    [B]    [B]    [B]
[A] -> [A] -> [A] -> [A] -> [A] -> [A]

If I don't use a name and instead use null when adding to the backstack I get the following: 如果我不使用名称,而是在添加到backstack时使用null,我会得到以下内容:

                                   [C]
                            [E]    [E]   
                     [D]    [D]    [D]    
              [C]    [C]    [C]    [C]   
       [B]    [B]    [B]    [B]    [B]  
[A] -> [A] -> [A] -> [A] -> [A] -> [A] 

How can I get the behaviour I expect? 我怎样才能得到我期望的行为? Is it possible at all or am I going to need to record the changes myself and skip the backstack altogether? 是否有可能或我是否需要自己记录更改并完全跳过后台堆叠?

There is no API to do this, but becuse I was wondering the same thing last week, 没有API可以做到这一点,但是因为我上周想知道同样的事情,
I took it as an exercise an implemented it myself. 我把它作为一个练习,自己实现它。

My method allows you to remove a Fragment from anywhere in the backstack and this is achieved by using refrection to modify the internal variables that store the backstack information in FragmentManagerImpl and BackStackRecord . 我的方法允许您从Backstack中的任何位置删除Fragment ,这可以通过使用refrection来修改存储FragmentManagerImplBackStackRecord中的Backstack信息的内部变量来实现。

There are few important variables: 几个重要变量:

  • mBackStack - stores the BackStackRecord s that hold the Fragment info, the previous ones, animations, etc mBackStack - 存储包含Fragment信息的BackStackRecord ,以前的,动画等
  • mActive - all added Fragment s mActive - 所有添加Fragment
  • mAvailBackStackIndices - stores the indices that can be used by the newly inserted records, ie indices of null values in mActive mAvailBackStackIndices - 存储新插入记录可以使用的索引,即mActivenullmActive
  • and other 和别的

Tested with 150+ Fragment s and couldn't notice any leaks, but only monitored the heap in DDMS and did not perform any other memory analysis. 使用150+ Fragment测试并且无法注意到任何泄漏,但仅监视DDMS的堆并且未执行任何其他内存分析。
So because someting may be broken, explore the code, re-test it, see if anyone provides a better answer, and rethink if you really need to do this in your project. 因此,可能会破坏某些方法,探索代码,重新测试它,看看是否有人提供了更好的答案,并重新考虑是否真的需要在项目中执行此操作。

I uploaded the code as a gist on GitHub , hope it helps. 我上传了代码作为GitHub要点 ,希望它有所帮助。

When you want to reuse the fragment before it, just first hide all the fragments and show the desired fragment at a time. 如果要在它之前重用片段,只需先隐藏所有片段并一次显示所需的片段。 By doing this you can reuse your fragments without removing them and without reloading the fragments. 通过这样做,您可以重用您的片段而无需删除它们,也无需重新加载片段。 But be sure before to implement it you have to add the fragment to backstack. 但是在实现之前一定要确保将片段添加到backstack中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM