Android实现Fragment单例复用 切换宿主时避免嵌套Fragment重建
首先明确:不要用传统类单例的私有构造方式实现Fragment单例,Fragment受FragmentManager生命周期管控,同一实例同时只能依附一个父容器,直接硬写单例很容易触发Fragment already added崩溃。正确方案是通过全局实例缓存+detach/attach复用的方式实现a、b切换时X不重建,具体实现步骤如下:
具体实现步骤
1. 给FragmentX实现全局实例缓存
保留Fragment必须的无参构造(否则系统内存回收后重建Fragment时会抛出实例化异常),通过静态字段缓存唯一实例,仅在第一次调用时初始化:
class FragmentX : Fragment() { companion object { private const val X_TAG = "GLOBAL_FRAGMENT_X" private var instance: FragmentX? = null fun getInstance(): FragmentX { if (instance == null) { instance = FragmentX() // 初始化参数只在这里设置一次,后续复用不要重复覆盖 // instance?.arguments = bundleOf("key" to "init value") } return instance!! } fun getFixedTag(): String = X_TAG } override fun onDestroyView() { super.onDestroyView() // 注意:不要在这里清空instance引用,否则下次加载会重新创建实例 } }
注意:不要给FragmentX自定义带参数的构造函数,所有初始化参数必须通过
arguments传递,避免系统重建时丢失参数。
2. 实现通用的X挂载逻辑,在a、b的onViewCreated中调用
切换父容器时,先将X从之前的容器detach(保留实例状态,不会触发onDestroy销毁),再挂载到当前容器,全程复用同一个实例,不会重复初始化:
// 在FragmentA、FragmentB中都调用这个方法加载X private fun attachFragmentX() { val xInstance = FragmentX.getInstance() val xTag = FragmentX.getFixedTag() val childFM = childFragmentManager // 如果X已经被添加到其他父容器,先从原容器detach保留实例 if (xInstance.isAdded) { xInstance.parentFragmentManager.beginTransaction() .detach(xInstance) .commitNowAllowingStateLoss() } val transaction = childFM.beginTransaction() // 查找当前容器是否已经存在X实例 val cachedX = childFM.findFragmentByTag(xTag) if (cachedX == null) { // 当前容器没有X,直接将缓存的全局实例添加到容器 transaction.replace(R.id.your_fragment_container_id, xInstance, xTag) } else { // 容器中已有X实例,直接attach显示即可 transaction.attach(cachedX) } // 注意:不要将该事务加入回退栈,避免返回逻辑错乱 transaction.commitNowAllowingStateLoss() }
必须规避的坑
- 全局给FragmentX使用固定统一的Tag,不要动态生成随机Tag,否则childFragmentManager无法正确识别已缓存的实例
- 切换容器时不要调用
remove()方法移除X,否则会触发实例销毁,必须用detach()保留实例状态 - 如果a、b通过ViewPager/ViewPager2实现切换,需要将离屏缓存数量设置为2,避免a、b自身被系统销毁重建导致嵌套Fragment状态异常
- 不要尝试让FragmentX同时依附在a、b两个容器上,Fragment机制不允许同一实例同时存在多个父布局,必定抛出异常
- 应用被系统回收后重建时,优先从FragmentManager通过Tag查找X实例,找不到再调用
getInstance(),避免状态恢复时实例不一致
内容的提问来源于stack exchange,提问作者Viacheslav Kolisnichenko
相关产品推荐
相关产品推荐

