LiveData 可观察数据持有者
LiveData 是一种可观察的数据持有者类。与常规的可观察类不同,LiveData 具有生命周期感知能力,这意味着它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。
为什么使用 LiveData?
- 确保界面符合数据状态: LiveData 遵循观察者模式。当底层数据发生变化时,LiveData 会通知观察者(通常是 UI 控制器),从而自动更新界面。
- 不会发生内存泄漏: 观察者绑定到
Lifecycle对象,并在相关生命周期销毁后自动清理。 - 不会因 Activity 停止而导致崩溃: 如果观察者的生命周期处于非活跃状态(如 Activity 在后台),则它不会接收任何 LiveData 事件。
- 自动更新配置更改: 如果 Activity 因配置更改(如旋转)而重建,它会立即接收最新的可用数据。
添加依赖
kotlin
dependencies {
val lifecycle_version = "2.8.0"
// LiveData 核心库
implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version")
}基本用法
创建 LiveData 对象
通常在 ViewModel 中定义。
kotlin
class MyViewModel : ViewModel() {
// 暴露给外部的不可变 LiveData
private val _currentName = MutableLiveData<String>()
val currentName: LiveData<String> get() = _currentName
fun changeName(newName: String) {
_currentName.value = newName
}
}观察 LiveData 对象
在 Activity 或 Fragment 的 onCreate 或 onViewCreated 中观察。
kotlin
class MyActivity : AppCompatActivity() {
private val model: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 观察数据变化
model.currentName.observe(this) { newName ->
// 更新 UI
binding.nameTextView.text = newName
}
}
}Fragment 中的观察
在 Fragment 中,请务必使用 viewLifecycleOwner 而不是 this 作为 LifecycleOwner,以避免视图销毁但 Fragment 存活导致的重复观察问题。
kotlin
model.data.observe(viewLifecycleOwner) { ... }进阶技巧
协程构建器 (liveData { ... })
这是将协程结果转换为 LiveData 的最优雅方式。它自动处理了生命周期:只有当 LiveData 有活跃观察者时,Block 内的代码才会执行;当观察者移除(超时)后,协程会自动取消。
kotlin
val user: LiveData<User> = liveData {
emit(User.LOADING)
try {
val data = repository.fetchUser() // 挂起函数
emit(data)
} catch (e: Exception) {
emit(User.ERROR)
}
}数据转换 (Transformations)
androidx.lifecycle.map 和 switchMap 扩展函数允许我们在数据分发给 UI 之前对其进行修改。
kotlin
val userId: LiveData<String> = ...
// 1. map: 同步转换 (1对1)
val userAvatarUrl: LiveData<String> = userId.map { id ->
"https://example.com/avatars/$id.png"
}
// 2. switchMap: 异步/流转换 (1对N)
// 当 userId 变化时,调用 repository 返回一个新的 LiveData,并自动切换观察
val userProfile: LiveData<UserProfile> = userId.switchMap { id ->
repository.getUserProfileLiveData(id)
}关键 API 区别
| 方法 | 描述 | 线程安全 |
|---|---|---|
setValue(T) | 立即在主线程更新数据。如果在子线程调用会崩溃。 | ❌ |
postValue(T) | 在后台线程任务中发布任务,最终由主线程更新数据。 | ✅ |
LiveData 与 Flow 的选择
建议
- 如果你的项目纯基于 Compose 且倾向于使用协程,建议优先使用
StateFlow或SharedFlow。 - 如果你使用的是传统的 XML 视图系统,或者希望利用极简的生命周期绑定,
LiveData依然是绝佳的选择。