关于Fragment处于后台被回收后,点击重启,Fragment页面无法做任何操作
开发过程中,出现过这样一个bug,在fragment跳转到系统权限设置页面,对权限进行开关后,返回app,app白屏重新启动,fragment页面仿佛被锁死,无法进行任何操作。
项目ui架构
MainActivity
- HomeFragment
- ListFragment
- AlarmFragment
- MineFragment
操作逻辑
HomeFragment
使用某个功能需要请求权限,当用户点击拒接不勾选不再提示后,当下次点击该功能时弹框提示用户跳转系统权限设置页面进行操作。(或者其它导致MainActivity处于后台被系统杀死回收的操作)
问题发现
当跳转到系统权限设置页面进行权限开关返回时,两种现象:
- App重启,重启一切正常;
- App不重启,白屏重新加载当前页面,加载完毕此
HomeFragment
无法操作。百分百复现。
问题排查
怀疑是Fragment生命周期出现问题,对MainActivity设置Log打印输出。以下是App不重启时日志输出总结:
- 打印生命周期,
MainActivity
重新走了onCreate()
方法,参数savedInstanceState
不为null。(推断App已经被系统杀死回收) - 打印
FragmentManager
的getFragments()
方法,输出两个HomeFragment
。(问题关键点) - 打印
FragmentTransaction
的getBackStackEntryCount()
,输出0。 - 打印
FragmentManager
的findFragmentByTag(String tag)
方法,输出全为null
结论
阅读FragmentManager、FragmentStore、FragmentTransaction、BackStackRecord
等系统源码,结合Activity、Fragment生命周期,Android系统回收机制等,可以得知当Activity被系统回收时,系统会将当前页面的数据保存在savedInstanceState,重新恢复时,系统会对这些对象进行恢复,但由于我们未重写数据保存和恢复的方法,所以系统恢复时并不是百分百完全复原,有些数据找不到,所以出现了add了相同的HomeFragment,而show的时候导致应该被回收的HomeFragment重叠在新add的HomeFragment上。
解决方法
最简单的方法,在MainActivity的onCreate方法中判断savedInstanceState是否为null,如果不为null,判断FragmentManager的getFragments()是否为空,不为空则将之前未销毁的fragment一个个销毁掉。
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
List<Fragment> list = fragmentManager.getFragments();
if(savedInstanceState != null && list.size() != 0){
for(Fragment fragment: list){
fragmentTransaction.remove(fragment);
fragmentTransaction.commitAllowingStateLoss();
}
}