LiveData
问题
LiveData 是什么?它和 Flow 相比有哪些优缺点?
答案
核心概念
LiveData 是一个具有生命周期感知能力的可观察数据容器。它只会在观察者处于活跃状态(STARTED 或 RESUMED)时发送更新,避免了崩溃和内存泄漏。
class UserViewModel : ViewModel() {
// 对内可变
private val _user = MutableLiveData<User>()
// 对外只读
val user: LiveData<User> = _user
fun loadUser(id: Long) {
viewModelScope.launch {
_user.value = repository.getUser(id) // 主线程赋值
// _user.postValue(user) // 子线程使用 postValue
}
}
}
// Activity 中观察
viewModel.user.observe(this) { user ->
binding.nameText.text = user.name
}
LiveData 操作符
// Transformations.map —— 数据转换
val userName: LiveData<String> = user.map { it.name }
// Transformations.switchMap —— 根据值切换数据源
val userItems: LiveData<List<Item>> = userId.switchMap { id ->
repository.getItemsLiveData(id)
}
// MediatorLiveData —— 合并多个源
val result = MediatorLiveData<String>()
result.addSource(liveData1) { result.value = combine(it, liveData2.value) }
result.addSource(liveData2) { result.value = combine(liveData1.value, it) }
LiveData vs Kotlin Flow
| 特性 | LiveData | StateFlow / SharedFlow |
|---|---|---|
| 生命周期感知 | ✅ 自动 | 需要 repeatOnLifecycle |
| 线程安全 | postValue | emit(协程安全) |
| 操作符 | 有限(map/switchMap) | 丰富(与 Kotlin 流一致) |
| 粘性事件 | ✅(新观察者收到最后值) | StateFlow 有,SharedFlow 可配置 |
| 背压处理 | 无 | 支持 |
| Java 兼容 | ✅ 好 | 需要额外适配 |
| 推荐场景 | 仅在 UI 层使用 | 推荐用 Flow 替代 |
官方建议
Google 官方推荐在新项目中使用 Kotlin Flow + repeatOnLifecycle 替代 LiveData。LiveData 仅在需要 Java 兼容时使用。
常见面试问题
Q1: LiveData 的粘性事件问题是什么?
答案:
新注册的 Observer 会立即收到 LiveData 中最后一次设置的值,这就是"粘性"。对于一次性事件(如 Toast、导航)来说会导致重复消费。
解决方案:
- 使用
SingleLiveEvent(Google 示例,但不推荐) - 封装
Event包装类,标记是否已消费 - 推荐:改用
SharedFlow(replay = 0)或Channel
// Event 包装类
open class Event<out T>(private val content: T) {
private var hasBeenHandled = false
fun getContentIfNotHandled(): T? =
if (hasBeenHandled) null else { hasBeenHandled = true; content }
}
Q2: setValue 和 postValue 的区别?
答案:
setValue():必须在主线程调用,同步更新值并立即通知观察者postValue():可在任何线程调用,通过 Handler 将更新 post 到主线程。如果连续调用多次,只有最后一次值生效
Q3: LiveData 是如何感知生命周期的?
答案:
LiveData.observe() 内部将 Observer 包装为 LifecycleBoundObserver,它实现了 LifecycleEventObserver:
- 当 Lifecycle 状态 >=
STARTED时,标记为活跃,分发数据 - 当 Lifecycle 状态 <
STARTED时,标记为非活跃,停止分发 - 当 Lifecycle 进入
DESTROYED时,自动移除 Observer