目录
  1. 1. 一、LiveData:生命周期感知的数据持有者
    1. 1.1. 1.1 LiveData 类图
  2. 2. 二、源码解析:订阅如何管理
    1. 2.1. 2.1 observe() 的内部流程
    2. 2.2. 2.2 observe() 完整源码分析
    3. 2.3. 2.3 LifecycleBoundObserver 的实现
    4. 2.4. 2.4 ObserverWrapper —— 版本号机制
    5. 2.5. 2.5 considerNotify() 方法
    6. 2.6. 2.6 dispatchingValue —— 数据分发核心
    7. 2.7. 2.7 setValue vs postValue 源码对比
  3. 3. 三、Transformations 数据变换
    1. 3.1. 3.1 Transformations.map() 源码
    2. 3.2. 3.2 Transformations.switchMap() 源码
    3. 3.3. 3.3 Transformations.distinctUntilChanged()
  4. 4. 四、MediatorLiveData 深度分析
    1. 4.1. 4.1 MediatorLiveData 的设计
    2. 4.2. 4.2 MediatorLiveData 的多源合并示例
  5. 5. 五、LiveData 的粘性事件问题与解决方案
    1. 5.1. 5.1 什么是粘性事件(Sticky Event)
    2. 5.2. 5.2 SingleLiveEvent 方案
    3. 5.3. 5.3 Event 包装器方案
    4. 5.4. 5.4 Kotlin Channel 方案(推荐)
  6. 6. 六、LiveData vs Kotlin Flow / StateFlow
    1. 6.1. 6.1 核心对比
    2. 6.2. 6.2 LiveData 与 Flow 的互转
    3. 6.3. 6.3 选择指南
  7. 7. 七、DataBinding 与 LiveData 的集成
  8. 8. 面试常考问题
JetPack全家桶(四)之LiveData数据存储器

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

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

LiveData 的架构定位很明确——它是 ViewModel 和 UI 之间的数据桥梁:

┌──────────┐      ┌───────────┐      ┌──────────┐
│ Repository│ ───► │ ViewModel │ ───► │ UI │
│ (Data) │ │ (LiveData)│ │(Observer)│
└──────────┘ └───────────┘ └──────────┘

生命周期感知
- 自动订阅/取消
- 只在活跃状态下更新
- 粘性事件

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

1.1 LiveData 类图

┌─────────────────────────┐
│ LiveData<T> │ (抽象类)
│ -mObservers: SafeIterableMap │
│ -mVersion: int │
│ -mData: T │
│ +observe(owner, observer)│
│ +observeForever(observer)│
│ +removeObserver(observer)│
│ #setValue(value) │
│ #postValue(value) │
│ #onActive() │
│ #onInactive() │
└──────────┬──────────────┘
│ extends
┌──────┴──────────────────┐
│ MutableLiveData<T> │
│ +setValue(value) │ (public)
│ +postValue(value) │ (public)
└─────────────────────────┘
│ extends
┌──────┴──────────────────┐
│ MediatorLiveData<T> │
│ +addSource(source, fn) │
│ +removeSource(source) │
└─────────────────────────┘

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

2.1 observe() 的内部流程

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 的观察者列表中移除自身,完成自动取消订阅。

2.2 observe() 完整源码分析

// LiveData.java
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
// 1. 必须在主线程调用
assertMainThread("observe");

// 2. 如果 LifecycleOwner 已经是 DESTROYED,不添加观察者
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
return; // 直接忽略,避免在已销毁的 Owner 上注册
}

// 3. 创建 LifecycleBoundObserver 包装器
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);

// 4. 检查是否已经存在同一个 Observer 的包装器
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
// 同一个 observer 不能绑定到两个不同的 LifecycleOwner
throw new IllegalArgumentException(
"Cannot add the same observer with different lifecycles");
}
if (existing != null) {
return; // 已经添加过了
}

// 5. 将包装器注册到 LifecycleOwner 的 Lifecycle 中
owner.getLifecycle().addObserver(wrapper);
}

2.3 LifecycleBoundObserver 的实现

// LiveData.java 内部类
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {

@NonNull
final LifecycleOwner mOwner;

LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}

@Override
boolean shouldBeActive() {
// 只有当 LifecycleOwner 的状态 >= STARTED 时才应该活跃
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}

@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
if (currentState == DESTROYED) {
// LifecycleOwner 销毁,移除观察者
removeObserver(mObserver);
return;
}

// 将 Observer 的状态同步到当前 Lifecycle 状态
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
activeStateChanged(shouldBeActive()); // 触发状态变化
currentState = mOwner.getLifecycle().getCurrentState();
}
}

@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}

@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}

2.4 ObserverWrapper —— 版本号机制

// LiveData.java 内部抽象类
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
boolean mActive; // Observer 是否活跃
int mLastVersion = START_VERSION; // Observer 最后收到的数据版本

ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}

abstract boolean shouldBeActive();

boolean isAttachedTo(LifecycleOwner owner) {
return false;
}

void detachObserver() {}

// 当活跃状态变化时调用
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return; // 状态未变,无需处理
}
mActive = newActive;

// 通知 LiveData 活跃观察者数量变化
changeActiveCounter(mActive ? 1 : -1);

if (mActive) {
// Observer 变为活跃,立即分发最新数据
dispatchingValue(this);
}
}
}

2.5 considerNotify() 方法

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

// LiveData.java
private void considerNotify(ObserverWrapper observer) {
// 1. 检查 Observer 是否活跃(LifecycleOwner 是否在 STARTED 以上)
if (!observer.mActive) {
return;
}

// 2. 检查 Observer 是否在前台(isAtLeast STARTED)
// 如果不在前台,说明其 Lifecycle 不在活跃状态,不推送
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}

// 3. 版本号检查:如果 Observer 已经收到过最新版本,不重复推送
if (observer.mLastVersion >= mVersion) {
return;
}

// 4. 更新 Observer 的版本号
observer.mLastVersion = mVersion;

// 5. 推送给 Observer
observer.mObserver.onChanged((T) mData);
}

2.6 dispatchingValue —— 数据分发核心

// LiveData.java
@SuppressWarnings("WeakerAccess")
void dispatchingValue(@Nullable ObserverWrapper initiator) {
// 避免递归分发
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;

do {
mDispatchInvalidated = false;

if (initiator != null) {
// 仅向特定 Observer 分发(如新注册或状态变为活跃时)
considerNotify(initiator);
initiator = null;
} else {
// 向所有 Observer 分发(如 setValue/postValue 调用时)
for (Map.Entry<Observer<? super T>, ObserverWrapper> entry :
mObservers.iteratorWithAdditions()) {
considerNotify(entry.getValue());
if (mDispatchInvalidated) {
// 在分发过程中有新 Observer 加入/移除,需要重新遍历
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}

2.7 setValue vs postValue 源码对比

// LiveData.java
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
// 递增版本号
mVersion++;
mData = value;
// 立即同步分发数据
dispatchingValue(null);
}

protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value; // 存储待分发的数据
}
if (!postTask) {
// 已有一个 post 任务待执行,不需要重复 post
// 但 mPendingData 已更新为最新值
return;
}
// 向主线程 post 一个 Runnable
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

// postValue 的 Runnable
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET; // 清空 pending
}
setValue((T) newValue); // 最终调用 setValue
}
};

关键设计点:

  1. setValue() 必须主线程,同步分发。
  2. postValue() 最终调用 setValue(),但通过主线程消息队列调度。
  3. postValue() 在 Runnable 未执行时多次调用,只有最后一次的值生效(前值被覆盖)。
  4. 版本号 mVersion 只在 setValue() 中递增,保证每次主线程更新都有一个唯一版本。

三、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
}

3.1 Transformations.map() 源码

// Transformations.java
@MainThread
public static <X, Y> LiveData<Y> map(
@NonNull LiveData<X> source,
@NonNull final Function<X, Y> mapFunction) {

final MediatorLiveData<Y> result = new MediatorLiveData<>();

result.addSource(source, new Observer<X>() {
@Override
public void onChanged(@Nullable X x) {
// 每次源数据变化时,应用 mapFunction 并设置结果
result.setValue(mapFunction.apply(x));
}
});

return result;
}

3.2 Transformations.switchMap() 源码

// Transformations.java
@MainThread
public static <X, Y> LiveData<Y> switchMap(
@NonNull LiveData<X> source,
@NonNull final Function<X, LiveData<Y>> switchMapFunction) {

final MediatorLiveData<Y> result = new MediatorLiveData<>();

result.addSource(source, new Observer<X>() {

LiveData<Y> mSource; // 当前活跃的源 LiveData

@Override
public void onChanged(@Nullable X x) {
LiveData<Y> newLiveData = switchMapFunction.apply(x);

if (mSource == newLiveData) {
return; // 同一个 LiveData 实例,无需重新绑定
}

// 移除旧的源
if (mSource != null) {
result.removeSource(mSource);
}

mSource = newLiveData;
if (mSource != null) {
// 添加新的源
result.addSource(mSource, new Observer<Y>() {
@Override
public void onChanged(@Nullable Y y) {
result.setValue(y);
}
});
}
}
});

return result;
}

switchMap 的典型使用场景:用户选择了一个 ID,根据 ID 从数据库或网络获取对应的详情数据。当用户快速切换 ID 时,switchMap 会自动取消旧请求的结果监听,只关注最新 ID 的结果——这个行为与 RxJava 的 switchMap 完全一致。

3.3 Transformations.distinctUntilChanged()

虽然 LiveData 没有内置此方法,但它是常用的扩展:

// 扩展函数:只有值真正变化时才通知观察者
fun <T> LiveData<T>.distinctUntilChanged(): LiveData<T> {
val output = MediatorLiveData<T>()
var firstTime = true
output.addSource(this) { value ->
val previous = output.value
if (firstTime || value != previous) {
firstTime = false
output.value = value
}
}
return output
}

四、MediatorLiveData 深度分析

4.1 MediatorLiveData 的设计

MediatorLiveData 是 LiveData 的子类,可以同时观察多个 LiveData 源。它是 Transformations.map()switchMap() 的底层实现基础。

// MediatorLiveData.java
public class MediatorLiveData<T> extends MutableLiveData<T> {

private SafeIterableMap<LiveData<?>, Source<?>> mSources = new SafeIterableMap<>();

@MainThread
public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
Source<S> e = new Source<>(source, onChanged);
Source<?> existing = mSources.putIfAbsent(source, e);
if (existing != null) {
// 同一个源只能添加一次
return;
}
if (hasActiveObservers()) {
// 如果 MediatorLiveData 本身有活跃观察者
e.plug(); // 开始监听源 LiveData
}
}

@MainThread
public <S> void removeSource(@NonNull LiveData<S> source) {
Source<?> sourceToRemove = mSources.remove(source);
if (sourceToRemove != null) {
sourceToRemove.unplug(); // 停止监听
}
}

// 当 MediatorLiveData 的第一个活跃观察者出现时
@Override
protected void onActive() {
for (Map.Entry<LiveData<?>, Source<?>> entry : mSources) {
entry.getValue().plug(); // 开始监听所有源
}
}

// 当 MediatorLiveData 的最后一个活跃观察者消失时
@Override
protected void onInactive() {
for (Map.Entry<LiveData<?>, Source<?>> entry : mSources) {
entry.getValue().unplug(); // 停止监听所有源
}
}

// 内部类:单个数据源的包装器
private static class Source<V> implements Observer<V> {
final LiveData<V> mLiveData;
final Observer<? super V> mObserver;
int mVersion = START_VERSION;

Source(LiveData<V> liveData, Observer<? super V> observer) {
mLiveData = liveData;
mObserver = observer;
}

void plug() {
mLiveData.observeForever(this); // 通过 observeForever 监听(不需要 LifecycleOwner)
}

void unplug() {
mLiveData.removeObserver(this);
}

@Override
public void onChanged(@Nullable V v) {
if (mVersion != mLiveData.getVersion()) {
mVersion = mLiveData.getVersion();
mObserver.onChanged(v); // 转发给 Transformations 的回调
}
}
}
}

关键设计:

  1. MediatorLiveData 使用 observeForever() 监听源 LiveData(不需要 LifecycleOwner)。
  2. 通过 onActive() / onInactive() 控制对源 LiveData 的监听——只有当 MediatorLiveData 自身有活跃观察者时才监听源,避免无用计算。
  3. 每个源封装为一个 Source 对象,通过版本号避免重复通知。

4.2 MediatorLiveData 的多源合并示例

// 同时观察多个 LiveData,任何一个变化时重新计算结果
class OrderSummaryViewModel : ViewModel() {
val price: LiveData<Double> = repository.getPrice()
val quantity: LiveData<Int> = MutableLiveData(1)
val discount: LiveData<Double> = MutableLiveData(0.0)

val total: MediatorLiveData<Double> = MediatorLiveData<Double>().apply {
var lastPrice = 0.0
var lastQuantity = 1
var lastDiscount = 0.0

fun updateTotal() {
value = lastPrice * lastQuantity * (1 - lastDiscount)
}

addSource(price) { p ->
lastPrice = p
updateTotal()
}
addSource(quantity) { q ->
lastQuantity = q
updateTotal()
}
addSource(discount) { d ->
lastDiscount = d
updateTotal()
}
}
}

五、LiveData 的粘性事件问题与解决方案

5.1 什么是粘性事件(Sticky Event)

LiveData 默认是粘性的——当新的 Observer 注册时,会立即收到 LiveData 中最后一次设置的值。这是设计特性而非 bug:

val data = MutableLiveData<String>()
data.value = "Hello"

// 在这里注册的 Observer 会立即收到 "Hello"
data.observe(lifecycleOwner) { value ->
// value == "Hello"
}

这个特性在多数场景下是优势(如配置变更后新 Activity 立即获取已有数据),但在处理一次性事件(如导航、Snackbar、Toast)时会成为问题:

// 问题场景
class MyViewModel : ViewModel() {
val navigateToDetail = MutableLiveData<Event<String>>()

fun onItemClick(itemId: String) {
navigateToDetail.value = Event(itemId) // 发射导航事件
}
}

class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.navigateToDetail.observe(this) { event ->
// 屏幕旋转后,Activity 重建,会再次收到旧的导航事件!
// 导致重复导航
}
}
}

5.2 SingleLiveEvent 方案

// SingleLiveEvent:只发送一次的事件包装器
class SingleLiveEvent<T> : MutableLiveData<T>() {

private val mPending = AtomicBoolean(false)

override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
// 内部维护一个包装 Observer,通过 AtomicBoolean 保证只发送一次
super.observe(owner) { t ->
if (mPending.compareAndSet(true, false)) {
observer.onChanged(t)
}
}
}

override fun setValue(t: T?) {
mPending.set(true)
super.setValue(t)
}

override fun postValue(value: T) {
mPending.set(true)
super.postValue(value)
}
}

5.3 Event 包装器方案

// 更灵活的事件包装器
class Event<out T>(private val content: T) {
private var hasBeenHandled = false

// 只允许消费一次
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}

// 查看内容但不消费
fun peekContent(): T = content
}

// 使用
class MyViewModel : ViewModel() {
val navigateToDetail = MutableLiveData<Event<String>>()

fun onItemClick(itemId: String) {
navigateToDetail.value = Event(itemId)
}
}

// Activity 中
viewModel.navigateToDetail.observe(this) { event ->
event.getContentIfNotHandled()?.let { itemId ->
// 只执行一次导航
navigateToDetail(itemId)
}
}

5.4 Kotlin Channel 方案(推荐)

// 使用 Channel 处理一次性事件,通过 Flow 收集
class MyViewModel : ViewModel() {
private val _navigationEvents = Channel<NavigationEvent>(Channel.BUFFERED)
val navigationEvents = _navigationEvents.receiveAsFlow()

fun onItemClick(itemId: String) {
viewModelScope.launch {
_navigationEvents.send(NavigationEvent.ToDetail(itemId))
}
}
}

// Activity 中
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.navigationEvents.collect { event ->
when (event) {
is NavigationEvent.ToDetail -> navigateToDetail(event.itemId)
}
}
}
}

Channel 方案的优势:

  • Channel 天然非粘性,发送的事件只被消费一次
  • 配合 repeatOnLifecycle,生命周期安全
  • 类型安全(使用 sealed class 定义所有事件)

六、LiveData vs Kotlin Flow / StateFlow

6.1 核心对比

特性 LiveData StateFlow SharedFlow
生命周期感知 是(自动) 否(需 repeatOnLifecycle)
平台 Android 专属 Kotlin 跨平台 Kotlin 跨平台
粘性 是(默认粘性) 是(always holds a value) 可配置(replay)
线程安全 部分(setValue 主线程,postValue 任意) 是(所有操作线程安全)
操作符 有限(map, switchMap) 丰富(Flow 全套操作符) 丰富
背压处理 有(conflated) 可配置
数据去重 是(自动 distinctUntilChanged) 可配置
多观察者 是(但每个 collector 独立)

6.2 LiveData 与 Flow 的互转

// LiveData -> Flow
fun <T> LiveData<T>.asFlow(): Flow<T> = callbackFlow {
val observer = Observer<T> { value -> trySend(value) }
observeForever(observer)
awaitClose { removeObserver(observer) }
}

// Flow -> LiveData
fun <T> Flow<T>.asLiveData(): LiveData<T> {
val liveData = MutableLiveData<T>()
// 在 Flow 收集时更新 LiveData
return liveData
}

// 官方提供的扩展(lifecycle-livedata-ktx)
// Flow.asLiveData() 内部使用 Channel 桥接
@JvmOverloads
fun <T> Flow<T>.asLiveData(
context: CoroutineContext = EmptyCoroutineContext,
timeoutInMs: Long = DEFAULT_TIMEOUT
): LiveData<T> = liveData(context, timeoutInMs) {
collect { value -> emit(value) }
}

6.3 选择指南

  • ViewModel -> UI:LiveData 仍是一个好选择(简单、生命周期安全、与 DataBinding 深度集成)。如果团队熟悉 Flow,也可以使用 StateFlow + repeatOnLifecycle。
  • Repository -> ViewModel:强烈推荐 Flow。冷流(cold flow)自动管理资源,丰富的操作符(map、filter、combine、catch、retry),不依赖 Android 平台。
  • 数据库观察:Room 原生支持 Flow 返回类型,配合 Flow 使用体验最好。
  • 一次性事件:Channel + Flow 优于 LiveData + Event 包装器。
  • 跨平台共享代码(KMM):只能用 Flow/StateFlow(LiveData 是 Android 专属)。

七、DataBinding 与 LiveData 的集成

DataBinding 与 LiveData 的集成是实现 MVVM 数据驱动 UI 的关键:

<!-- layout 文件 -->
<layout>
<data>
<variable name="viewModel" type="com.example.MyViewModel" />
</data>

<LinearLayout>
<!-- LiveData 自动绑定,LifecycleOwner 决定更新时机 -->
<TextView
android:text="@{viewModel.userName}"
android:visibility="@{viewModel.isLoading ? View.GONE : View.VISIBLE}" />
</LinearLayout>
</layout>
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.lifecycleOwner = this // 关键:设置 LifecycleOwner
binding.viewModel = viewModel
}
}

DataBinding + LiveData 的工作流程:

  1. DataBinding 在编译期生成 LiveDataListener,它实现了 Observer 接口。
  2. 当 View 绑定了一个 LiveData 表达式时,DataBinding 自动调用 liveData.observe(lifecycleOwner, observer)
  3. lifecycleOwner 控制 Observer 的活跃状态。
  4. 当 LiveData 值变化且 Observer 活跃时,DataBinding 自动更新 View。

面试常考问题

Q1: LiveData 与 Kotlin Flow / StateFlow 的对比与选择?

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

关键区别:

  • LiveData 通过 LifecycleBoundObserver 自动管理订阅生命周期,Observer 在 DESTROYED 时自动移除。
  • StateFlow 需要通过 repeatOnLifecycle(STARTED) 手动管理生命周期。
  • StateFlow 自动去重(distinctUntilChanged),LiveData 每次 setValue() 都会通知(即使值相同)。
  • StateFlow 是热流(hot flow),始终持有最新值;LiveData 也是粘性的,但通过 observeForever 可以观察到所有更新。
  • StateFlow 有结构化的并发支持(stateIn()),Flow 有丰富的终止操作符(first()take() 等)。

Q2: postValue 和 setValue 的区别?

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

源码流程分析:

postValue(value):
1. synchronized(mDataLock) { mPendingData = value; }
2. if (!postTask): 已经有一个 post 任务在排队,直接更新 mPendingData 后返回
3. ArchTaskExecutor.postToMainThread(mPostValueRunnable)

mPostValueRunnable.run():
1. synchronized(mDataLock) { newValue = mPendingData; mPendingData = NOT_SET; }
2. setValue(newValue) // 在主线程调用

这意味着:

  • 如果你连续 3 次调用 postValue("A"), postValue("B"), postValue("C"),Observer 可能只收到 "C"(中间的 “A” 和 “B” 被覆盖)。
  • setValue 每次调用都会分发,Observer 会依次收到 “A”, “B”, “C”。
  • postValue 适合子线程更新,setValue 适合主线程更新。

Q3: LiveData 数据倒灌(Sticky Event)是什么?如何解决?

A: LiveData 默认是粘性的——新的观察者注册时会立即收到最后一次发射的数据。这在处理一次性事件(如导航指令、Snackbar)时会导致问题:屏幕旋转后重建的 Activity 会再次收到旧导航事件。

三种解决方案:

  1. SingleLiveEvent:内部用 AtomicBoolean 控制事件只被消费一次。
  2. Event 包装器:Event.getContentIfNotHandled() 返回 null 如果已被消费。
  3. Channel + Flow(推荐):Channel 天然非粘性,配合 repeatOnLifecycle 实现生命周期安全的单次事件消费。

为什么粘性事件是”特性”而非”bug”?在多数场景下,粘性事件是需要的——比如屏幕旋转后,新的 Activity 需要立即获取 ViewModel 中已有的用户信息数据,而无需重新加载。粘性只在处理一次性事件时才成为问题。

Q4: LiveData 的活跃状态判断逻辑是什么?

A: LiveData 判断 Observer 是否”活跃”的核心逻辑在 LifecycleBoundObserver.shouldBeActive() 中:

boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}

只有 LifecycleOwner 的状态 >= STARTED(即 STARTED 或 RESUMED)时,Observer 才是活跃的。

完整的状态转换:

  • CREATED -> STARTED(对应 onStart):Observer 变为活跃,activeStateChanged(true) 被调用,立即收到最新数据。
  • STARTED -> CREATED(对应 onStop):Observer 变为非活跃,activeStateChanged(false) 被调用,停止接收数据。
  • Lifecycle.DESTROYED:Observer 被自动移除,完全取消订阅。

这意味着:

  • Activity 在后台(onStop 之后)不会再收到 LiveData 更新,不会触发不必要的 UI 刷新。
  • Fragment 在 back stack 中(onStop 之后)也不会收到更新。
  • 一旦回到前台(onStart),会立即收到最新的数据,确保 UI 显示的是最新状态。

Q5: MediatorLiveData 与 combine 操作符有什么区别?何时使用?

A: MediatorLiveData 可以手动添加多个源并通过回调自定义合并逻辑。它是命令式的:你显式调用 addSource() 并编写合并逻辑。而 Flow 的 combine 操作符是声明式的。

// MediatorLiveData(命令式)
val result = MediatorLiveData<String>()
result.addSource(liveData1) { v1 ->
result.value = "$v1-${liveData2.value}"
}
result.addSource(liveData2) { v2 ->
result.value = "${liveData1.value}-$v2"
}

// Flow combine(声明式)
val result: Flow<String> = combine(flow1, flow2) { v1, v2 ->
"$v1-$v2"
}

选择建议:

  • 只有一个或两个源:MediatorLiveData 更简单直接。
  • 三个及以上源:Flow 的 combine 更清晰,不易出错。
  • 需要复杂的数据流处理(如 debounce、throttle、retry):Flow 有丰富的操作符。
  • 需要与 DataBinding 集成:LiveData 是 DataBinding 的原生支持类型。

核心参考 AOSP 路径:

  • lifecycle/livedata-core/src/main/java/androidx/lifecycle/LiveData.java — LiveData 核心实现
  • lifecycle/livedata-core/src/main/java/androidx/lifecycle/ObserverWrapper.java — Observer 包装器
  • lifecycle/livedata-core/src/main/java/androidx/lifecycle/Transformations.java — 数据变换
  • lifecycle/livedata-core/src/main/java/androidx/lifecycle/MediatorLiveData.java — 多源合并
  • lifecycle/livedata-ktx/src/main/java/androidx/lifecycle/LiveData.kt — Kotlin 扩展
  • lifecycle/lifecycle-common/src/main/java/androidx/lifecycle/LifecycleRegistry.java — 生命周期管理
  • databinding/library/src/main/java/android/databinding/DataBindingUtil.java — DataBinding 集成
打赏
  • 微信
  • 支付宝

评论