自定义View中调用findViewTreeLifecycleOwner()的最佳位置?
自定义View中调用
findViewTreeLifecycleOwner()的最佳时机 不同调用位置的时序适配性
结合Fragment 1.3.0引入ViewTreeLifecycleOwner的实现逻辑,不同View生命周期节点的调用结果如下:
- 构造函数、
init块、onFinishInflate():这些节点的执行时机早于Fragment在onViewCreated()阶段给根视图设置LifecycleOwner标记的动作,此时沿视图树查找永远返回null,完全不适合调用。 onAttachedToWindow():执行时机晚于Fragment的onViewCreated()阶段,此时视图树的LifecycleOwner标记已经设置完成,findViewTreeLifecycleOwner()可以稳定返回非空实例,是当前可选的最适配的调用位置。
为什么onAttachedToWindow()是合理选择
从设计逻辑和生命周期对齐角度看,在该位置执行初始化调用完全合理:
- 该节点是View正式和窗口建立绑定关系的起点,和“借助协程完成视图初始化”的目标完全匹配——视图还没attach到窗口时,就算启动协程任务,也没有可承载初始化结果的实际视图显示环境。
- 从这个节点获取的
lifecycleScope会和当前关联的LifecycleOwner绑定,当View脱离窗口、关联的LifecycleOwner销毁时,协程任务会自动取消,不需要手动处理资源释放,从根源上避免内存泄漏。 - 该节点的执行时序和Fragment的视图生命周期是天然对齐的:Fragment执行完
onCreateView()、onViewCreated()设置好LifecycleOwner标记后,等所有视图完成inflate、attach到窗口时才会依次触发每个View的onAttachedToWindow()回调,不存在找不到LifecycleOwner的时序问题。
实际使用的注意事项
- 禁止直接对
findViewTreeLifecycleOwner()做非空强转:当View被用在没有关联LifecycleOwner的场景(比如非Fragment承载的普通视图场景)时,该方法会返回null,直接强转会导致崩溃,需要做判空兜底。 - 注意View的attach和detach是成对触发的:当View在窗口间移动、从父视图临时移除再重新添加时,会重复触发
onAttachedToWindow()回调,要保证放在这里的协程初始化逻辑是幂等的,避免重复执行造成资源浪费。 - 如果需要更严格的生命周期对齐,可以在拿到LifecycleOwner后,判断当前
lifecycle.currentState,仅在符合预期状态时启动协程任务。
调整后的安全示例代码
class TestView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : LinearLayout(context, attrs, defStyleAttr) { override fun onAttachedToWindow() { super.onAttachedToWindow() val owner = findViewTreeLifecycleOwner() ?: return owner.lifecycleScope.launchWhenStarted { // 执行需要协程支撑的初始化逻辑 } } }
内容的提问来源于stack exchange,提问作者Benjamin Ledet
相关产品推荐
相关产品推荐

