Android 生命周期监听演进与对应实现

用一条时间线说明「生命周期监听」如何从 Activity 里手写对称回调,演进为 Lifecycle + DefaultLifecycleObserver、Fragment 的 viewLifecycleOwner,再到与协程配合的 repeatOnLifecycle + Flow,并对应各阶段在解决什么问题、今天该怎么选。


一、演进主线与时间线

Android 生命周期监听的发展,可以概括成一条主线:把生命周期管理从 UI 控制器里抽出去,交给 Lifecycle 与可组合的 API,让组件能声明式地「跟着生命周期走」

flowchart LR
  p1["手写对称回调"]
  p2["AAC 与 @OnLifecycleEvent"]
  p3["DefaultLifecycleObserver"]
  p4["viewLifecycleOwner"]
  p5["repeatOnLifecycle + Flow"]
  p1 --> p2 --> p3 --> p4 --> p5
阶段大致年代
手写对称回调AAC 出现长期存在;约 2017 年前仍是主流做法
AAC 与 @OnLifecycleEvent约 2017 起随 Architecture Components 发布并推广
DefaultLifecycleObserver约 2018 起接口写法随 AndroidX 普及;Lifecycle 2.4(约 2021–2022 稳定) 废弃 @OnLifecycleEvent,迁移到接口为主
viewLifecycleOwner约 2019 前后起,随 Fragment 区分「实例 / View」生命周期成为常规选项
repeatOnLifecycle + FlowLifecycle 2.4 一代协程与生命周期文档一并普及,用于按可见性收集 Flow

二、第一阶段:手写回调的「刀耕火种」时代

1. 典型写法

Activity / Fragment 的生命周期方法里,手动调用业务组件的注册与注销。

class MyActivity : AppCompatActivity() {
    private val locationListener = MyLocationListener()

    override fun onStart() {
        super.onStart()
        locationListener.start()
    }

    override fun onStop() {
        locationListener.stop()
        super.onStop()
    }
}

2. 为什么会被取代?(痛点)


三、第二阶段:AAC Lifecycle 与注解时代(约 2017)

为解决上述问题,Google 在 Android Architecture Components(AAC)中引入 LifecycleLifecycleOwner:组件可以注册为观察者,自己响应生命周期事件,UI 层只负责 addObserver

1. 典型写法:@OnLifecycleEvent

class MyLocationListener : LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun start() { /* 开始定位 */ }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun stop() { /* 停止定位 */ }
}

class MyActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        lifecycle.addObserver(MyLocationListener())
    }
}

2. 注解路径:为何出现,又因何废弃?


四、第三阶段:接口化——DefaultLifecycleObserver

废弃 @OnLifecycleEvent 并不是放弃 Lifecycle 模型本身,而是把「按需订阅生命周期」交给接口默认实现这一更合适的语言特性。注解退场后,推荐写法是显式实现接口:DefaultLifecycleObserverLifecycleEventObserver。其中日常最常用的是 DefaultLifecycleObserver:各生命周期方法在接口中有默认空实现,你只 override 关心的即可,无反射、契约清晰

1. 典型写法

class MyLocationListener : DefaultLifecycleObserver {
    override fun onStart(owner: LifecycleOwner) { /* 开始定位 */ }
    override fun onStop(owner: LifecycleOwner) { /* 停止定位 */ }
}

lifecycle.addObserver(MyLocationListener())

2. 为何这是当前推荐的「生命周期感知组件」基底?

更多说明见官方指南:Handling Lifecycles


五、支线:Fragment 与 viewLifecycleOwner

这条支线为什么重要:Fragment 实例的生命周期和它内部 View 的生命周期不同步;只绑 fragment.lifecycle 操作 UI,会在返回栈等场景下踩坑。

1. 痛点场景

当 Fragment 进入返回栈(BackStack)时,View 会被销毁(走到 onDestroyView),但 Fragment 实例仍存在。若某个监听仍挂在 Fragment 的 lifecycle 上,异步回调回来时去更新已销毁的 TextView 等控件,轻则 NPE,重则 泄漏已销毁的 View 引用

2. 正确做法:viewLifecycleOwner

viewLifecycleOwner 表示 Fragment 中 View 的生命周期。凡是与界面绑定的观察、协程作用域,应使用 viewLifecycleOwner.lifecycle / viewLifecycleOwner.lifecycleScope,这样在 onDestroyView 时会自动与 View 对齐、解绑。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    // 当 View 销毁时,Observer 会随 view 生命周期结束而移除
    viewLifecycleOwner.lifecycle.addObserver(MyUIObserver())

    // 错误示例:Fragment 在返回栈、View 已无时,仍可能收到回调并更新 UI
    // lifecycle.addObserver(MyUIObserver())
}

详见:Fragment 生命周期 中对 viewLifecycleOwner 的说明。


六、第四阶段:协程、Flow 与 repeatOnLifecycle

LiveData 曾常与生命周期配合使用;在 Kotlin 中转向 Flow / StateFlow 后,collect 默认不感知生命周期:若在 Activity/Fragment 里长时间 collect,应用进入后台时仍可能持续收集,浪费 CPU 与电量

1. 过渡期的别扭写法(应淘汰)

onStart 里启动协程收集、onStop 里取消,本质上又回到手写对称生命周期的老路,易错且难读。

2. 推荐写法:repeatOnLifecycle

lifecycleScope(Fragment 中与 UI 相关时用 viewLifecycleOwner.lifecycleScope)里使用 repeatOnLifecycle:在生命周期至少到达某一状态(如 STARTED)时执行块内逻辑;低于该状态时取消块内协程;再次进入时重新执行。这样与「前后台可见性」对齐,避免后台空转收集。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    viewLifecycleOwner.lifecycleScope.launch {
        repeatOnLifecycle(Lifecycle.State.STARTED) {
            viewModel.uiState.collect { state ->
                // 更新 UI
            }
        }
    }
}

说明与注意事项见:将 Kotlin 协程与生命周期感知组件一起使用(含 lifecycleScoperepeatOnLifecycle 等用法)。


七、落地速查

演进的主线是:生命周期管理从 UI 层外移,由 LifecycleviewLifecycleOwnerrepeatOnLifecycle 等标准 API 表达「何时启动、何时停止、与谁绑定」。日常写代码可直接按下表选型。

场景当前推荐做法
编写生命周期感知的组件实现 DefaultLifecycleObserver,使用 lifecycle.addObserver() 注册
在 Fragment 中操作 UI绑定到 viewLifecycleOwner.lifecycle(及对应的 lifecycleScope
在 Kotlin 中收集 Flow / StateFlowviewLifecycleOwner.lifecycleScope + repeatOnLifecycle(Lifecycle.State.STARTED)
进程级前后台判断ProcessLifecycleOwner.get().lifecycle