目录
  1. 1. 一、LiveData:生命周期感知的数据持有者
  2. 2. 二、源码解析:订阅如何管理
  3. 3. 三、Transformations 数据变换
  4. 4. 面试常考问题
JetPack全家桶(四)之LiveData数据存储器

一、LiveData:生命周期感知的数据持有者

LiveData 是一个可被观察的数据容器类,区别于传统 Observable,它会自动感知观察者(LifecycleOwner)的生命周期状态。具体表现为:当观察者的生命周期处于 STARTED 或 RESUMED 时,LiveData 才向其推送数据更新;当观察者的生命周期变为 DESTROYED 时,订阅关系自动移除。这从根本上杜绝了”Activity 已销毁、回调仍更新 UI”这类经典的 IllegalStateException 和内存泄漏问题。

LiveData 有两个常用变体:MutableLiveData 提供了 postValue()(子线程安全)和 setValue()(主线程)用于更新数据;MediatorLiveData 可同时观察多个 LiveData 源,并在任一源变化时进行合并处理,适合多数据源聚合场景。

二、源码解析:订阅如何管理

LiveData 的 observe() 方法内部创建了一个 LifecycleBoundObserver,它同时实现了 LifecycleEventObserverObserverWrapper。当调用 observe(owner, observer) 时,这个包装器被传给 LifecycleRegistry.addObserver(),从而让 Observer 与 LifecycleOwner 的状态同步。

源码核心逻辑(/lifecycle/livedata-core/src/main/java/androidx/lifecycle/LiveData.java):

observe(LifecycleOwner owner, Observer<T> observer) ->
new LifecycleBoundObserver(owner, observer) ->
owner.getLifecycle().addObserver(wrapper)

当 LifecycleOwner 状态变为 DESTROYED 时,LifecycleRegistry 调用 onStateChanged(DESTROYED)LifecycleBoundObserver 随即从 LiveData 的观察者列表中移除自身,完成自动取消订阅。

considerNotify() 方法在分发数据前调用 shouldBeActive() 检查观察者生命周期,只有处于 STARTED 及以上状态才会真正调用 observer.onChanged()。这就是 LiveData 不会向已停止的 Activity 推送更新的根本机制。

三、Transformations 数据变换

LiveData 提供了 Transformations.map()Transformations.switchMap() 两个工具,类似于 RxJava 的 map 和 flatMap:

val userId: LiveData<Int> = MutableLiveData(1)

// map: 将一种 LiveData 转换为另一种
val userName: LiveData<String> = Transformations.map(userId) { id ->
"User_$id"
}

// switchMap: 自动切换数据源
val user: LiveData<User> = Transformations.switchMap(userId) { id ->
repository.getUserById(id) // 当 userId 变化时自动切换到新的 LiveData
}

面试常考问题

Q1: LiveData 与 Kotlin Flow / StateFlow 的对比与选择?
A: LiveData 生命周期感知能力强,自动处理订阅/取消,与 Android UI 天然绑定——但它是 Android 平台专属,不适用于纯 Kotlin 模块。StateFlow 是 Kotlin 协程生态的一部分,跨平台可用,配合 repeatOnLifecycle 也能实现安全的 UI 数据收集。选择建议:ViewModel 与 UI 之间的通信仍可使用 LiveData,Repository/DataSource 层的数据流使用 Flow,通过 asLiveData() 扩展函数可无缝转换。

Q2: postValue 和 setValue 的区别?
A: setValue() 必须在主线程调用,立即同步更新数据并通知观察者。postValue() 可在任意线程调用,它将值加入主线程的消息队列中异步执行(内部通过 ArchTaskExecutor.postToMainThread() 实现)。源码中 postValue 还有一个保护:如果在主线程的 Runnable 尚未执行前多次调用 postValue,只有最后一次的值会被分发,中间值会被覆盖。

Q3: LiveData 数据倒灌(Sticky Event)是什么?如何解决?
A: LiveData 默认是粘性的——新的观察者注册时会立即收到最后一次发射的数据。这在处理一次性事件(如导航指令、Snackbar)时会导致问题:屏幕旋转后重建的 Activity 会再次收到旧导航事件。解决方案:使用 SingleLiveEvent(只发送一次的消息包装器)或改用 Channel + Flow 配合 collect 代替 LiveData 处理一次性事件。

打赏
  • 微信
  • 支付宝

评论