Android Navigation组件搭配ViewPager2调用navigateUp返回后无法访问内部Fragment异常问题
问题原因分析
- Fragment回退栈的状态保存机制:当你跳转到其他Fragment时,FragmentMain会被压入回退栈,此时它的视图层会被销毁,但Fragment实例本身以及关联的
childFragmentManager状态会被完整保留,之前ViewPager2挂载的所有Fragment实例都被存储在childFragmentManager的缓存中,不会被销毁。 - 重复初始化Adapter的逻辑缺陷:你在每次
onViewCreated生命周期执行时都重新创建MyFragmentStateAdapter实例并绑定到ViewPager2,但ViewPager2在状态恢复阶段会优先复用childFragmentManager中已经存在的Fragment实例,不会使用新Adapter生成的Fragment。你在页面上看到的保留状态就是这些旧Fragment实例渲染的,新Adapter创建的Fragment确实从未被挂载到视图上。 - 无法获取Fragment引用的根本原因:
FragmentStateAdapter内部会维护一份自己创建过的Fragment缓存,但你每次都新建Adapter实例,旧Adapter的缓存随着旧视图销毁被回收,新Adapter的缓存是空的,所以通过新Adapter实例自然访问不到实际显示的Fragment实例。 - 功能不受影响的原因:因为实际运行的Fragment实例和共享ViewModel绑定的生命周期是正常的,所以通过ViewModel交互的逻辑可以正常执行,只有直接持有Adapter引用访问Fragment的逻辑会失效。
实际挂载的Fragment引用保存位置
所有正在显示和被ViewPager2缓存的Fragment实例,都保存在FragmentMain的childFragmentManager中。FragmentStateAdapter默认生成的Fragment的tag固定格式为 f + ViewPager2的id + : + 位置下标,你可以通过以下代码直接获取指定位置的Fragment实例:
val targetFragment = childFragmentManager.findFragmentByTag("f${binding.viewPager2.id}:$position")
修复方案
不需要每次在onViewCreated中重新创建Adapter,只需要在Fragment第一次初始化时创建一次Adapter实例并保存,后续返回FragmentMain时直接复用即可,之后就可以通过Adapter实例正常访问内部的Fragment引用。
内容的提问来源于stack exchange,提问作者March3April4
相关产品推荐
相关产品推荐

