概述
LiveData 能够感知与其关联的 LifecycleOwner (如 Activity、Fragment) 的生命周期,仅当 LifecycleOwner 处于started 或 resumed 状态时,LiveData 才会通知观察者数据的变化,避免无效的 UI 更新。
原理
LiveData 核心是关联 LifecycleOwner(Activity/Fragment)的生命周期:LiveData 内部会向 LifecycleOwner 注册 LifecycleEventObserver,监听其生命周期状态变化;当宿主生命周期状态为 destroyed 时,LiveData 会自动移除观察者,无需手动处理,还从根源避免内存泄漏。
LiveData 核心源码
// LiveData 内部的生命周期绑定观察者(核心内部类)
private class LifecycleBoundObserver(
val lifecycleOwner: LifecycleOwner,
val observer: Observer<in T>
) : Observer<T>, LifecycleEventObserver {
// 监听生命周期事件变化
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
val currentState = source.lifecycle.currentState
// 核心1:如果宿主已销毁(DESTROYED),自动移除观察者
if (currentState == Lifecycle.State.DESTROYED) {
removeObserver(observer) // 自动解绑,避免内存泄漏
return
}
// 核心2:判断宿主是否处于活跃状态(STARTED/RESUMED)
var prevState: Lifecycle.State? = null
if (prevState != currentState) {
val isActive = currentState.isAtLeast(Lifecycle.State.STARTED)
// 更新观察者的活跃状态
activeStateChanged(isActive)
}
}
// 数据变更时的回调(仅当活跃时才触发)
override fun onChanged(t: T) {
if (isActive) { // isActive 由上面的生命周期状态决定
observer.onChanged(t) // 通知外部观察者
} else {
// 非活跃状态:暂存数据(粘性事件的基础),等活跃后再通知
pendingData = t
}
}
}
关键方法对比(核心重点)
| 方法 | 使用线程 | 特点 | 适用场景 |
|---|---|---|---|
| setValue(T value) | 必须主线程 | 同步更新数据,立即通知观察者 | 主线程中修改数据(如按钮点击、UI 交互、实时状态变更) |
| postValue(T value) | 可子线程 / 主线程 | 异步更新数据(通过 Handler 切主线程),若多次调用仅最后一次生效 | 子线程中修改数据(如网络请求、数据库查询后更新数据) |
优点(核心价值)
- ✅ 生命周期感知能力:自动适应 UI 组件的生命周期,避免在组件不可见时执行不必要的数据更新操作,降低性能消耗。
- ✅ 线程安全能力:适配多线程场景,setValue 保证主线程安全、postValue 自动切主线程,避免 UI 线程异常崩溃。
- ✅ 无内存泄漏问题:宿主销毁时自动解绑观察者,彻底避免 Activity/Fragment 泄漏;数据释放与 ViewModel 生命周期强绑定,资源回收更高效。
应用(计数器示例)
以一个简单的计数器为例,实现MVVM 架构下的单向数据流:
ViewModel(核心:解耦 View 与数据,封装业务逻辑)
处理业务逻辑,持有可观察数据,与 View 解耦,无需持有任何 View 引用,即使 activity 销毁,viewmodel 数据仍保留
// 自定义 ViewModel,存放计数器数据
class CounterViewModel : ViewModel() {
// 1. MutableLiveData:可变的 LiveData(可修改值),仅在 ViewModel 内部使用,**[开闭原则]**
private val _counter = MutableLiveData<Int>(0)
// 2. LiveData:不可变的暴露给外部(只读),**保证数据安全**,避免外部随意改值
val counter: LiveData<Int> = _counter
// 3. 提供修改数据的方法(外部通过调用方法更新,而非直接改值)
fun incrementCounter() {
// 获取当前值(为空则默认 0),+1 后更新
_counter.value = (_counter.value ?: 0) + 1
}
}
View(核心:仅负责 UI 展示与用户交互,不处理业务逻辑)
show UI、接收用户交互,不处理业务数据逻辑,通过 observe 监听 viewmodel 的 livedata 刷新 UI
class CounterActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 获取 viewmodel(生命周期独立,配置变更不丢失)
val viewModel = ViewModelProvider(this)[CounterViewModel::class.java]
// 绑定控件
val tvCounter = findViewById<TextView>(R.id.tv_counter)
val btnAdd = findViewById<Button>(R.id.btn_add)
// 观察Livedata变化(生命周期感知,自动解绑)
viewModel.counter.observe(this) { newCount ->
tvCounter.text = "当前计数:$newCount"
}
// 接收用户交互,调用ViewModel方法修改数据
btnAdd.setOnClickListener {
viewModel.incrementCounter()
}
}
}
LiveData 粘性事件(核心特性)
LiveData 存在粘性事件特性:若 LiveData 先发送了数据,之后再注册观察者,观察者仍能收到这条历史数据。
✅ 场景示例:ViewModel 中先请求网络数据并更新 LiveData,此时 Activity 还未创建;Activity 创建后观察 LiveData,仍能收到网络请求的结果,无需重新请求。
⚠️ 注意:若不需要粘性事件(如单次事件传递),需自定义 LiveData 屏蔽该特性(如使用 SingleLiveEvent 或 EventWrapper)。
核心总结
- 生命周期感知是 LiveData 的核心基础,仅活跃状态下通知 UI 更新,兼顾性能与体验;
- setValue/postValue 是线程安全的核心,需严格匹配使用线程,避免崩溃;
- 私有 MutableLiveData + 暴露只读 LiveData 是数据安全的最佳实践,符合 MVVM 单向数据流规范;
- 粘性事件是 LiveData 的默认特性,需根据业务场景选择是否启用。