ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

LiveData observe 注册和接收信息

2026/8/9 1:38:35 拓冰建站 浏览量
LiveData observe 注册和接收信息
class LifecycleDemo1ViewModel : ViewModel() { //写入 private var _userName = MutableLiveData<String>() //对外只读 val userName: LiveData<String> = _userName fun testPostValue(){ viewModelScope.launch() { _userName.postValue("test kotlin") //注意和setValue的区别} } }
第一种通用写法: demo1ViewModel.userName.observe(this){ name -> Log.d("AAA", "1 userName = " + name) } 第二种回调onChanged比较容易理解 demo1ViewModel.userName.observe(this, object : Observer<String>{ override funonChanged(value: String) { Log.d("AAA", "2 userName = " + value) } })子线程使用:postValue 主线程使用:setValue 最终子线程postValue也会转换成主线程调用setValue的 使用观察者模式,observe注册:owner.getLifecycle().addObserver(wrapper);observer.mObserver.onChanged((T) mData); // 最终回调你的 Lambda

我们从源码级别postValueonChanged的每一步彻底拆解。这个过程可以精确划分为4 个阶段

为了让你看透本质,我会带上源码中的关键变量名(基于 AndroidX Lifecycle 2.x 版本)。


阶段 1:postValue—— 线程调度与暂存

当你调用_userName.postValue("test kotlin")时,源码内部做了两件事:

java

// LiveData.java 源码 private volatile Object mPendingData = NOT_SET; // 暂存变量 private final Runnable mPostValueRunnable = new Runnable() { @Override public void run() { Object newValue = mPendingData; mPendingData = NOT_SET; // 取出后立即清空 setValue((T) newValue); } }; protected void postValue(T value) { boolean postTask; synchronized (mDataLock) { postTask = mPendingData == NOT_SET; // 判断是否已有未处理的任务 mPendingData = value; // ① 将新值暂存到 mPendingData } if (!postTask) { return; // 如果已经有任务排队,直接返回,只更新暂存值 } // ② 通过主线程 Handler 发送 Runnable ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); }

关键细节

  • mPendingData是“暂存位”:不管主线程是否空闲,postValue总是立即把新值赋值给mPendingData

  • 防高频堆积:如果当前主线程消息队列里已经有一个mPostValueRunnable在排队了,再次调用postValue时,postTaskfalse不会再发送新的 Runnable。这意味着:高频调用postValue时,只会触发一次主线程任务,但暂存的值会被覆盖为最后一次设置的值。


阶段 2:主线程执行Runnable—— 调setValue

当主线程空闲,Looper 取出这个消息,执行mPostValueRunnablerun()

java

// 接上面的 run() public void run() { Object newValue = mPendingData; mPendingData = NOT_SET; // ① 取走并清空暂存 setValue((T) newValue); // ② 调用 setValue }

进入setValue(T value)

java

@MainThread protected void setValue(T value) { assertMainThread("setValue"); // 确保在主线程 synchronized (mDataLock) { mData = value; // ① 正式更新内部数据 mVersion++; // ② 版本号自增 +1 } dispatchingValue(null); // ③ 触发分发 }

关键细节

  • 此时数据才算真正存入mData(LiveData 持有的最终值)。

  • mVersion自增是通知的核心依据。初始版本通常是-1,每次setValue都会+1


阶段 3:dispatchingValue—— 遍历与并发保护

进入dispatchingValue(null)(传null代表通知所有观察者):

java

void dispatchingValue(@Nullable ObserverWrapper initiator) { if (mDispatchingValue) { // 如果正在分发中 mDispatchInvalidated = true; // 打标记,不重复遍历 return; } mDispatchingValue = true; do { mDispatchInvalidated = false; // 遍历所有观察者(存储在 SafeIterableMap 中) for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { if (mDispatchInvalidated) break; // 如果被标记失效,重来 considerNotify(iterator.next().getValue()); // 逐一通知 } } while (mDispatchInvalidated); mDispatchingValue = false; }

关键细节

  • 防并发修改:如果在遍历过程中,有新的观察者注册或数据再次变更,会通过mDispatchInvalidated标记,让外层do-while重新遍历,保证所有观察者都能收到最新状态,不会崩溃。


阶段 4:considerNotify—— 生命周期检查 + 粘性触发(最终回调)

这是决定你能否收到回调的“最后一关”:

java

private void considerNotify(ObserverWrapper observer) { if (!observer.mActive) return; // 如果宿主(Activity)已销毁,直接跳过 // 核心:检查宿主的当前生命周期是否 >= STARTED if (!observer.shouldBeActive()) { observer.activeStateChanged(false); return; } // 关键:粘性逻辑判断 if (observer.mLastVersion >= mVersion) { return; // 如果观察者记录的版本号 >= 当前版本号,说明已分发过,跳过 } observer.mLastVersion = mVersion; // 更新观察者的版本号observer.mObserver.onChanged((T) mData); // 最终回调你的 Lambda}

两个关键过滤条件

  1. 生命周期屏障(可见性)
    shouldBeActive()检查的是LifecycleOwner的状态是否为STARTEDRESUMED
    如果你的 Activity 在后台(PAUSED),此处直接返回,不会执行回调,避免更新 UI 崩溃。

  2. 版本号屏障(粘性/防重复)
    即使生命周期满足,如果observer.mLastVersion == mVersion,也不回调。
    但你的场景中,postValue使mVersion0变成了1,而新注册的observer.mLastVersion初始是-1,因为-1 < 1,所以条件通过,立刻回调—— 这就是“粘性”的源码体现。


总结:一张时序图帮你串起来

text

子线程调用 postValue("test") │ ├─ ① 存入 mPendingData = "test" └─ ② 向主线程发消息 (Handler) (主线程空闲后) ↓ ③ 执行 Runnable:取出 mPendingData ④ 调用 setValue("test") ├─ mData = "test" ├─ mVersion++ (比如 0→1) └─ ⑤ dispatchingValue(null) │ ├─ 遍历 mObservers (包含你注册的监听) └─ ⑥ considerNotify(你的观察者) ├─ 检查生命周期 (STARTED?) ✅ ├─ 检查版本 (-1 < 1) ✅ └─ ⑦ 回调 onChanged("test") 🎉