一、Lifecycle 的核心原理:状态机与观察者模式
说实话,Lifecycle 是我在 Jetpack 里最先爱上的组件。为什么?因为它解决了一个困扰 Android 开发者多年的老问题——组件生命周期管理混乱。
你想想看,以前我们是怎么管理生命周期的?在 Activity 的 onCreate 里初始化,onDestroy 里释放。如果有个第三方库要监听生命周期,要么写一堆回调接口,要么用 EventBus 满天飞。代码耦合度高得吓人。
Lifecycle 的核心思想其实很简单:把生命周期状态抽象成一个状态机,然后用观察者模式通知订阅者。
1.1 状态机:生命周期到底有几个状态?
很多人以为生命周期就是 onCreate、onStart、onResume 这些回调方法。但 Lifecycle 的抽象更精细。它把生命周期分成了两种概念:状态(State) 和 事件(Event)。
- State:当前组件所处的生命周期阶段。比如
CREATED、STARTED、RESUMED、DESTROYED。 - Event:状态之间的转换动作。比如
ON_CREATE、ON_START、ON_RESUME、ON_PAUSE、ON_STOP、ON_DESTROY。
我画了一张状态机流转图,你看一眼就明白了:
这张图我建议你保存下来。每次写 Lifecycle 相关代码时,对照着看,思路会清晰很多。
1.2 观察者模式:谁在监听谁?
Lifecycle 用了标准的观察者模式。LifecycleOwner 是被观察者,LifecycleObserver 是观察者。当生命周期状态发生变化时,LifecycleOwner 会遍历所有注册的观察者,逐个通知。
核心接口就三个:
// 被观察者:拥有生命周期的组件
public interface LifecycleOwner {
Lifecycle getLifecycle();
}
// 生命周期抽象类
public abstract class Lifecycle {
public abstract void addObserver(LifecycleObserver observer);
public abstract void removeObserver(LifecycleObserver observer);
public abstract State getCurrentState();
}
// 观察者标记接口
public interface LifecycleObserver {}
嗯,这里要注意:LifecycleObserver 本身是个空接口。真正干活的是它的子接口 DefaultLifecycleObserver 或者注解方式 @OnLifecycleEvent。
核心要点:Lifecycle 的观察者模式不是简单的回调,而是基于状态机的增量通知。什么意思?比如当前状态是 STARTED,新注册一个观察者,它会收到 ON_CREATE 事件,而不是直接跳到当前状态。这保证了观察者能完整感知生命周期的变化过程。
二、LifecycleOwner 与 LifecycleObserver 的绑定机制
绑定过程,说白了就是「观察者注册」和「事件分发」两个步骤。我拆开来讲。
2.1 注册过程:addObserver 干了什么?
当你调用 lifecycle.addObserver(observer) 时,内部做了三件事:
- 包装观察者:把
LifecycleObserver包装成ObserverWithState,里面存了观察者的注解方法和当前状态。 - 状态同步:如果当前生命周期状态已经大于
INITIALIZED,会从ON_CREATE开始,把缺失的事件逐个补发。 - 存储引用:把包装后的对象存入
FastSafeIterableMap,保证遍历时的线程安全。
我贴一段简化后的源码,你感受一下:
// LifecycleRegistry.java (简化版)
public void addObserver(LifecycleObserver observer) {
State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
// 存入 map
mObserverMap.putIfAbsent(observer, statefulObserver);
// 状态同步:补发缺失的事件
while (statefulObserver.mState.compareTo(mState) < 0
&& mObserverMap.contains(observer)) {
Event event = Event.upFrom(statefulObserver.mState);
if (event == null) break;
statefulObserver.dispatchEvent(this, event);
}
}
我在项目中遇到过一个问题:在 onResume 里注册观察者,结果 onCreate 事件没收到。后来看了源码才明白——addObserver 会补发事件,但补发是从 INITIALIZED 开始往上推的。所以即使你在 onResume 注册,也能收到 ON_CREATE 和 ON_START。这个设计很巧妙,对吧?
2.2 事件分发:状态变更时发生了什么?
当 Activity 执行 onStart 时,ReportFragment 会调用 lifecycle.handleLifecycleEvent(ON_START)。内部逻辑是这样的:
// LifecycleRegistry.java
public void handleLifecycleEvent(Event event) {
State next = getStateAfter(event);
moveToState(next);
}
private void moveToState(State next) {
mState = next;
// 遍历所有观察者,逐个分发事件
sync();
}
sync() 方法会遍历 mObserverMap,对每个观察者调用 dispatchEvent。如果观察者实现了 DefaultLifecycleObserver,就调用对应的回调方法;如果是注解方式,就用反射调用。
性能提示:DefaultLifecycleObserver 是 Java 8 接口,用 default 方法实现,没有反射开销。而 @OnLifecycleEvent 注解方式依赖反射,性能略差。我个人习惯在新项目里全部用 DefaultLifecycleObserver。
三、自定义 LifecycleOwner 实战
有时候我们需要让自定义类也拥有生命周期管理能力。比如一个自定义 View,或者一个后台服务。怎么做?实现 LifecycleOwner 接口,然后用 LifecycleRegistry 管理状态。
3.1 一个完整的自定义 LifecycleOwner 示例
假设我们有一个 TimerManager,需要管理定时器的生命周期:
class TimerManager : LifecycleOwner {
private val lifecycleRegistry = LifecycleRegistry(this)
override fun getLifecycle(): Lifecycle = lifecycleRegistry
fun start() {
// 模拟生命周期变化
lifecycleRegistry.currentState = Lifecycle.State.STARTED
// 开始定时器...
}
fun stop() {
// 停止定时器...
lifecycleRegistry.currentState = Lifecycle.State.CREATED
}
fun destroy() {
lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
}
}
使用的时候:
val timerManager = TimerManager()
timerManager.lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
println("定时器启动了")
}
override fun onDestroy(owner: LifecycleOwner) {
println("定时器销毁了,释放资源")
}
})
timerManager.start()
// 业务逻辑...
timerManager.destroy()
注意:LifecycleRegistry 不是线程安全的。如果你在多线程环境下调用 setCurrentState,需要自己加锁。我曾经在协程里直接调用,结果遇到了并发修改异常。后来用 synchronized 包了一层才解决。
3.2 什么时候需要自定义 LifecycleOwner?
我总结了三个典型场景:
- 自定义 View:比如一个视频播放器 View,需要根据页面生命周期暂停/恢复播放。
- 后台 Service:比如定位服务,需要在 Activity 销毁时自动停止定位。
- 测试环境:单元测试中模拟生命周期变化,验证观察者行为。
四、在 ViewModel 中优雅管理生命周期
ViewModel 本身就是一个 LifecycleOwner,但它的生命周期和 Activity/Fragment 不同。ViewModel 的生命周期是「从创建到页面销毁」,不受屏幕旋转等配置变更影响。
4.1 ViewModel 的生命周期范围
看这张对比表就清楚了:
| 组件 | 生命周期范围 | 典型场景 |
|---|---|---|
| Activity | onCreate ~ onDestroy | 屏幕旋转会重建 |
| Fragment | onAttach ~ onDetach | 随 Fragment 生命周期 |
| ViewModel | 创建 ~ 页面彻底销毁 | 屏幕旋转不重建 |
ViewModel 的 onCleared() 方法会在页面彻底销毁时调用。我习惯在这里释放一些重量级资源,比如网络请求的协程 Job。
4.2 在 ViewModel 中使用 Lifecycle
ViewModel 本身不直接持有 Activity 的 Lifecycle,但我们可以通过 SavedStateHandle 或者 ProcessLifecycleOwner 来感知应用级别的生命周期。
举个例子,我想在 App 进入后台时暂停数据刷新,回到前台时恢复:
class DataRefreshViewModel : ViewModel() {
private val refreshJob = SupervisorJob()
private val scope = CoroutineScope(refreshJob + Dispatchers.IO)
init {
// 监听应用前后台切换
ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
startRefreshing()
}
override fun onStop(owner: LifecycleOwner) {
stopRefreshing()
}
})
}
private fun startRefreshing() {
scope.launch {
while (isActive) {
// 刷新数据
delay(30_000)
}
}
}
private fun stopRefreshing() {
refreshJob.cancelChildren()
}
override fun onCleared() {
super.onCleared()
refreshJob.cancel()
}
}
最佳实践:ViewModel 里不要直接持有 Activity 或 Fragment 的引用,否则会导致内存泄漏。用 ProcessLifecycleOwner 或者 LiveData 来间接感知生命周期,才是正道。
4.3 避坑指南:我曾经踩过的坑
我曾经在 ViewModel 里直接调用了 lifecycle.addObserver(),结果发现 ViewModel 的 lifecycle 属性返回的是 LifecycleRegistry,但它的状态始终是 CREATED,不会自动变化。后来才意识到——ViewModel 的 Lifecycle 需要手动管理,不像 Activity 那样有系统自动驱动。
正确的做法是:如果 ViewModel 需要感知 Activity 的生命周期,通过 LiveData 或者 Flow 把生命周期事件传递进来,而不是直接依赖 ViewModel 自身的 Lifecycle。
嗯,关于 Lifecycle 的核心内容,今天就聊到这里。这个组件看似简单,但用好了能让你的代码结构清晰很多。记住一句话:让生命周期管理回归组件本身,而不是散落在各个回调里。