Skip to content

LiveData 可观察数据持有者

源: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 的 onCreateonViewCreated 中观察。

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.mapswitchMap 扩展函数允许我们在数据分发给 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 且倾向于使用协程,建议优先使用 StateFlowSharedFlow
  • 如果你使用的是传统的 XML 视图系统,或者希望利用极简的生命周期绑定,LiveData 依然是绝佳的选择。