嵌套ViewPager未清理Fragment问题:未设适配器却提前创建Fragment致崩溃
1. 外层ViewPager的Fragment销毁重建逻辑
你切换到第4页时,外层levelOneViewPager的默认离屏缓存参数offscreenPageLimit默认值为1,会销毁超出缓存范围的第1页Fragment实例。当你切回第1页时,系统会先尝试恢复之前销毁的第1页Fragment的所有状态,包括它内部嵌套的所有子Fragment(也就是levelTwoViewPager对应的子Fragment),这个恢复操作是在父Fragment的onAttach、onCreate阶段就执行的,远早于onViewCreated生命周期。
2. 嵌套Fragment恢复优先级高于父Fragment视图初始化
系统恢复子Fragment的操作完全不受你是否给levelTwoViewPager设置适配器的控制:只要父Fragment之前添加过子Fragment,销毁时系统就会把这些子Fragment的状态保存到childFragmentManager的状态栈里,父Fragment重建时,childFragmentManager会第一时间恢复这些子Fragment实例,触发它们的生命周期回调。这时候你还没走到onViewCreated里加载内层ViewPager数据、设置适配器的逻辑,子Fragment访问父Fragment未初始化的数据就会直接崩溃。
3. 更换PagerAdapter无效的原因
不管是FragmentPagerAdapter还是FragmentStatePagerAdapter,本质都是通过父Fragment的childFragmentManager管理子Fragment实例,只要childFragmentManager里有之前保存的子Fragment状态,重建时都会优先恢复,和你后续什么时候给ViewPager设置适配器没有关联。
- 将内层ViewPager需要的共享数据初始化逻辑从
onViewCreated提前到父Fragment的onCreate阶段,保证在系统恢复子Fragment之前,父Fragment的共享数据已经初始化完成 - 子Fragment访问父Fragment的数据时增加空校验,数据未初始化完成时先展示占位状态,等父Fragment数据加载完成、给内层ViewPager设置适配器后再刷新子Fragment内容
- 如果外层ViewPager总页数≤5,可直接设置
levelOneViewPager.offscreenPageLimit = 总页数,避免第1页Fragment被销毁,从根源上避免重建恢复逻辑 - 需要彻底禁用子Fragment提前恢复时,可在父Fragment的
onCreate方法里加入以下代码,清空之前保存的子Fragment状态:
// Kotlin示例 if (savedInstanceState != null) { val savedState = childFragmentManager.saveState() childFragmentManager.restoreState(savedState, null) }
// Java示例 if (savedInstanceState != null) { FragmentManager childFM = getChildFragmentManager(); Parcelable savedState = childFM.saveState(); childFM.restoreState(savedState, null); }
内容的提问来源于stack exchange,提问作者AndroidDev

