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

用途:梳理 Android 生命周期监听机制的发展脉络对应时代的实现方式,以及为什么会发生这些演进。理解了「痛点与解法」,写代码时自然就能选对 API。
建议阅读顺序:先看 一、当前最佳实践速查(结论),再按时间线阅读「为什么这么发展」。


一、当前最佳实践速查(结论)

不管历史怎么变,现在写代码请认准以下规范:

场景当前推荐做法淘汰/避坑的做法
写生命周期感知的组件(如相机、传感器)实现 DefaultLifecycleObserver,用 lifecycle.addObserver() 注册❌ 不再使用 @OnLifecycleEvent 注解
在 Fragment 中操作 UI(如更新 TextView)必须绑定 viewLifecycleOwner.lifecycle❌ 不要绑定 Fragment 自身的 lifecycle
Kotlin 中收集 Flow / StateFlowviewLifecycleOwner.lifecycleScope + repeatOnLifecycle(STARTED)❌ 不要直接在协程里裸 collect(后台耗电)
进程级前后台判断ProcessLifecycleOwner.get().lifecycle❌ 不要在 BaseActivity 里自己计数

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

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。组件终于可以「自己监听」生命周期了。

1. 对应实现

通过 @OnLifecycleEvent 注解标记方法,实现解耦。

// 组件自己管理自己
class MyLocationListener : LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun start() { /* 开始定位 */ }

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

// UI 层只管注册,其他不用管
class MyActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        lifecycle.addObserver(MyLocationListener())
    }
}

2. 为什么当时不直接用接口?(历史局限)

2017 年 AAC 刚发布时,Android 主流环境还是 Java 7。 如果当时使用接口(比如包含 onCreateonDestroy 6 个方法的接口),任何实现该接口的类都必须写出这 6 个方法的空实现,哪怕它只需要监听 onStart。这会导致大量冗余的样板代码。如果不这么做,就得提供一个 Adapter 抽象类让大家去继承,但这又会吃掉 Java 宝贵的「单继承」名额。 为了让代码保持简洁且不占用继承位,Google 选择了通过注解 @OnLifecycleEvent 让开发者「按需标记」方法。

3. 为什么后来又演进并废弃了注解?(痛点)

随着 Android 环境的升级,注解机制的劣势逐渐暴露:


四、第三阶段:接口化时代(现代 Java/Kotlin 标配)

1. 对应实现

废弃注解,全面转向显式的接口回调:DefaultLifecycleObserverLifecycleEventObserver

class MyLocationListener : DefaultLifecycleObserver {
    // 接口自带 default empty implementation,按需重写即可
    override fun onStart(owner: LifecycleOwner) { /* 开始定位 */ }
    override fun onStop(owner: LifecycleOwner) { /* 停止定位 */ }
}

// 注册方式不变
lifecycle.addObserver(MyLocationListener())

2. 为什么这么发展?


五、支线演进:Fragment 的「视图生命周期」分离 (2018)

在 Fragment 的使用中,开发者遇到了一个致命的坑:Fragment 的实例生命周期Fragment 内部 View 的生命周期 是不一致的。

1. 痛点场景

当 Fragment 被放入返回栈(BackStack)时,它的 View 会被销毁(调用 onDestroyView),但 Fragment 实例本身还活着。 如果在此时,某个绑在 Fragment lifecycle 上的网络请求回来了,去更新已经被销毁的 TextView,就会直接 Crash(NullPointerException)或者发生内存泄漏。

2. 演进后的实现:viewLifecycleOwner

Google 引入了 viewLifecycleOwner,专门代表 Fragment 内部 View 的生命周期。只要是操作 UI 的监听,必须绑定到它上面。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    // ✅ 正确:当 View 销毁时,这个 Observer 就会自动解绑
    viewLifecycleOwner.lifecycle.addObserver(MyUIObserver())
    
    // ❌ 错误:如果 Fragment 在返回栈里,View 已经没了,这个 Observer 还在跑
    // lifecycle.addObserver(MyUIObserver())
}

六、第四阶段:协程与 Flow 时代 (2021 至今)

在响应式编程时代,LiveData 曾经是王,因为它自带生命周期感知。但随着 Kotlin 协程和 Flow 的崛起,LiveData 的能力显得不够用了(不支持复杂操作符、必须在主线程等)。 当大家转向 Flow 时,发现 Flow 的 collect 是不感知生命周期的——如果应用退到后台,Flow 还在默默收集,会疯狂消耗 CPU 和电量。

1. 早期妥协实现(已淘汰)

开发者被迫写丑陋的样板代码,在 onStart 里启动协程收集,在 onStop 里取消协程,一夜回到「刀耕火种」时代。

2. 最终演进实现:repeatOnLifecycle

Google 推出了 repeatOnLifecycle API,完美结合了协程的特性与生命周期感知。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    // 1. 绑定视图生命周期的协程作用域
    viewLifecycleOwner.lifecycleScope.launch {
        // 2. 声明:当生命周期至少到达 STARTED 时,执行 block;
        // 当生命周期低于 STARTED(退到后台)时,取消 block;
        // 再次回到前台时,重新执行 block。
        repeatOnLifecycle(Lifecycle.State.STARTED) {
            viewModel.uiState.collect { state ->
                // 更新 UI
            }
        }
    }
}

3. 为什么这么发展?


七、总结:演进的底层逻辑

Android 生命周期监听的发展,其实是一条主线:「把复杂的生命周期管理,从 UI 层剥离,下沉到框架和组件内部」

  1. 解耦:从 Activity.onStart 手写 → LifecycleOwner 让组件自己管自己。
  2. 性能与规范:从 @OnLifecycleEvent 注解反射 → DefaultLifecycleObserver 接口重写。
  3. 精准与安全:从粗放的 Fragment lifecycle → 专门针对 UI 的 viewLifecycleOwner
  4. 适应现代语言:从 LiveData 的强绑定 → repeatOnLifecycle 结合 Kotlin Flow 的优雅挂起与恢复。

八、补充说明:语言演进史对框架设计的影响(番外篇)

把 Android Lifecycle API 的设计放到当时的语言环境时间轴上,很多「不合理」的设计就变得顺理成章: