Fragment回退栈相关操作
在我的场景里,会创建多个Fragment,Fragment之间可以互相跳转,点击返回键需要一级一级往上返回。因此需要一个类似于Activity的回退栈,当然没必要做到Activity那么复杂,满足先进先出的效果即可。
添加Fragment回退栈
添加个Fragment,并将其加入回退栈,代码如下:
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.add(R.id.frag_container, fragment)
.addToBackStack(null)
.commitAllowingStateLoss();
方法addToBackStack
表示将Fragment加入到回退栈中。
在返回时,Fragment出栈的逻辑如下:
FragmentManager fragmentManager = getSupportFragmentManager();
int backStackCount = fragmentManager.getBackStackEntryCount();
if (backStackCount > 0) {
fragmentManager.popBackStack();
}
方法popBackStack
将一个Fragment出栈,调用前可以先通过getBackStackEntryCount
方法判断当前回退栈是否还有Fragment。
获取顶部的Fragment
我的场景中,经常要获取栈顶的Fragment进行操作,然而没有找到直接获取栈顶Fragment的方法。在最初的实现中,借用了Stack
来实现我的逻辑。
private final Stack<Fragment> mFragmentStack = new Stack<>();
public void addFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.add(R.id.frag_container, fragment)
.addToBackStack(null)
.commitAllowingStateLoss();
mFragmentStack.push(fragment);
}
public void popFragment() {
FragmentManager fragmentManager = getSupportFragmentManager();
int backStackCount = fragmentManager.getBackStackEntryCount();
if (backStackCount > 0) {
fragmentManager.popBackStack();
mFragmentStack.pop();
}
}
public Fragment getTopFragment() {
return mFragmentStack.peek();
}
然而使用Stack
后发现线上版本会发生crash。mFragmentStack
里的Fragment和FragmentManager中的Fragment可能不一致。主要原因是Activity状态恢复导致的,Stack数据没有saveInstanceState,Activity恢复时执行mFragmentStack.peek
会导致EmptyStackException
。
要修复这个问题,可以将Stack数据也进行状态保存。但我仔细想过后觉得,Stack和FragmentManager的作用是一致的,加一个Stack本身是不合理的,后续代码变更,也很难保证Stack和FragmentManager回退栈数据是一致的。为此我开始想另外的解决方案。
回到我最开始的需求,我就是想获取顶部的Fragment,能不能用FragmentManager提供的接口来实现呢?阅读相关源码后,有个方法引起了我的注意:
/**
* Return the BackStackEntry at index <var>index</var> in the back stack;
* entries start index 0 being the bottom of the stack.
*/
@NonNull
public BackStackEntry getBackStackEntryAt(int index) {
return mBackStack.get(index);
}
获取到的BackStackEntry
有id和name属性,为此我想到一个办法:
public Fragment getTopFragment() {
int count = getSupportFragmentManager().getBackStackEntryCount();
FragmentManager.BackStackEntry entry = getSupportFragmentManager().getBackStackEntryAt(count - 1);
return getSupportFragmentManager().findFragmentByTag(entry.getName());
}
该代码中,首先获取回退栈数量,然后通过getBackStackEntryAt
方法,获取最后一个回退栈数据。最后通过findFragmentByTag
找到顶部的Fragment。不过这里要注意的是,在添加回退栈时,需要设置tag。具体代码如下:
public void addFragment(Fragment fragment) {
String tag = getFragmentTag();
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.add(R.id.frag_container, fragment, tag)
.addToBackStack(tag)
.commitAllowingStateLoss();
}
上面代码中,add和addToBackStack方法都指定了同一个tag,保证后续能够通过findFragmentByTag
找到相应的Fragment。
方案最终验证OK。
热门相关:斗神战帝 霸皇纪 时间都知道 寂静王冠 豪门闪婚:帝少的神秘冷妻