LiveData 原理与源码解读
核心概述
LiveData 是一种可感知生命周期的数据持有者,支持 UI 组件安全地订阅数据变化。通过生命周期感知、粘性/非粘性分发策略与主线程保证,LiveData 降低了内存泄漏与状态错位的风险。
架构组成
- LiveData:抽象基类,维护数据版本、活跃观察者数量与主线程调度。
- MutableLiveData:允许写入数据的实现,
postValue/setValue控制线程安全更新。 - ObserverWrapper:封装
Observer并记录其活跃状态、最后接收版本。 - LifecycleBoundObserver:继承自
ObserverWrapper,与LifecycleOwner绑定,自动在销毁时移除。 - MediatorLiveData:支持合并多个 LiveData 源的数据变更。
数据分发流程
- 调用
observe(owner, observer)时,LiveData 创建LifecycleBoundObserver并注册至LifecycleOwner。 - 当生命周期状态达到
STARTED及以上时,LifecycleBoundObserver标记为活跃,通过activeStateChanged(true)触发数据分发。 setValue会更新内部mVersion,并通过dispatchingValue遍历活跃观察者,比较ObserverWrapper.lastVersion决定是否回调onChanged。postValue在子线程写入mPendingData,通过主线程 Handler 切换到setValue。
java
// LiveData 值更新核心逻辑
protected void setValue(T value) {
assertMainThread("setValue")
mVersion++
mData = value
dispatchingValue(null)
}
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) { mDispatchInvalidated = true; return; }
mDispatchingValue = true
do {
mDispatchInvalidated = false
if (initiator == null) {
forEachObserver(observer -> considerNotify(observer))
} else {
considerNotify(initiator)
initiator = null
}
} while (mDispatchInvalidated)
mDispatchingValue = false
}关键源码细节
- 版本控制:每次
setValue会递增mVersion,观察者仅在observer.lastVersion < mVersion的情况下收到通知,避免重复回调。 - 线程模型:
assertMainThread确保读写在主线程执行,postValue借助ArchTaskExecutor切换线程。 - 粘性事件:普通
observe默认接收最新一次数据,若需要非粘性可使用observeForever+ 手动控制版本或封装 SingleLiveEvent。 - 主动移除:
removeObserver/removeObservers及时释放引用,避免页面退出后继续持有。
实践建议
- 对协程 Flow 可使用
asLiveData()转换,指定Dispatchers控制线程。 - 对非粘性需求,封装基于
MediatorLiveData的事件总线,手动消费后重置。 - 使用
Transformations.map/switchMap或 KotlinliveData {}构建派生数据。 - 在测试中借助
InstantTaskExecutorRule强制同步执行。
风险与调试
- 数据倒灌:活动重建时 LiveData 会再次发送最新值,应区分数据状态与一次性事件。
- 线程问题:
postValue合并多次调用,最终只分发最后一次;需要逐条分发可结合队列或 Channel。 - 调试可覆写
observe时记录Lifecycle状态,结合Debug版本开启日志。