调用observe()方法时,第一个参数传入LifecycleOwner对象,而LifecycleOwner能通过getLifecycle()方法获取到lifecycle对象,然后执行lifecycle.addObserver()添加LiveData中数据(mData)变化的观察者对象。
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer super T> observer) {
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        owner.getLifecycle().addObserver(wrapper);
    }
 

如上图所示,是使用LiveData组件实现数据更新-订阅的开发模式的层级结构。
中的值赋值给mData变量,然后就是走setValue()的流程了。
该类是Observer的包装类,是一个抽象类,具体实现类是LifecycleBoundObserver,内部包裹了mOwner、mObserver、mActive、mLastVersion变量,如下:
private abstract class ObserverWrapper {
     final Observer super T> mObserver;
     boolean mActive;
     // 初始值是-1,LiveData的初始值是0,那么第一次对比时
     // observer.mLastVersion肯定是小于mVersion的,一定会更新一次值
     int mLastVersion = START_VERSION;
}
 
在ObserverWrapper包装mLastVersion和mObserver的基础上,把LifecycleOwner(中文咋说?生命周期所有者嘛?这不重要,方正不外乎Activty、Fragment、或者自己实现的自定义生命周期组件)也包装了进来,
主要是为了拿到当前Activity/Fragment的生命周期状态,做一些逻辑,比如:onDestroy时要removeObserver,判断当前是否时活跃状态,也就是isAtLeast(STARTED)状态,我们在编写业务代码时也经常传递这个参数给到子模块,完成对于生命周期组件的状态判断、添加、移除生命周期监听的observer对象等逻辑。
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
        @NonNull final LifecycleOwner mOwner;
		// 将LifecycleOwner对象包装到其中,用户实现一些生命周期的逻辑,
	    // 也能直接拿到lifecycle对象,其实现就是Activity、Fragment。
        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer super T> observer) {
            super(observer);
            mOwner = owner;
        }
        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }
        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }
        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }
        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }
 
这是在androidx.core.common库中定义的一个map结构,仔细看下其实是一个链表实现的,实现的是迭代器接口。

private SafeIterableMap, ObserverWrapper> mObservers = new SafeIterableMap<>(); 
(1)onStart()之后调用setValue()立即回调onChanged(newData)
(2)调用observe()时,如果Observer是新建的实例,那么其绑定的mLastVersion初始值是-1,当调用lifecycleOwner.addObserver()时会调用activeStateChanged(), 然后触发dispatchingValue(), 因为不满足observe.mLastVersion>=mVersion(默认值是0,每次setValue/postValue加1),然后回调onChanged(newData)
如果是在onStop()中注册observer,那么会在回到onStart()后会回调一次onChanged()
⚠️ LiveData中判断LifecycleOwner是判断生命周期状态是否是isAtLeast(START),所以onPause时调用observe()方法也是会回调onChanged()方法的。
(3)LifecycleOwner生命周期变化时,还存在同因生命周期     LiveData其实本质上实现的是将事件发送时机限定在LifecycleOwner的生命周期内的粘性事件。LiveData在生命周期可见时,将不可见时更新的mData版本回传到onChanged()中,当setValue()是在observe()之前调用的,那调用observe()时会把前面setValue的最新的值传给观察者的onChanged()。这个被观察者的变量是否有更新过的逻辑,主要靠LiveData类中定义的mVersion和ObserverWrapper的mLastVersion对比逻辑来实现的。3、说LiveData会数据倒灌是这么回事?
 
3.1 本质
 
setValue调用分发value的逻辑很好理解,onActiveStateChanged方法在调用observe()方法增加新观察者时也会调用,然后根据版本决定是否调用observer的onChangd方法。
    @SuppressWarnings("unchecked")
    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
        //
        // we still first check observer.active to keep it as the entrance for events. So even if
        // the observer moved to an active state, if we've not received that event, we better not
        // notify for a more predictable notification order.
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }
 
不使用LiveData进行数据更新时,一般是在UI控件变量准备好了,然后获取数据,再把数据传递给UI控件变量的某个属性,实现UI的更新,这种命令式UI的开发模式本身没有什么问题,符合日常的开发逻辑。
但是因为Android的UI架构都是基于Activity/Fragment生命周期管理的,就必然存在数据异步获取到时界面已经处于不活跃状态的情况。甚至很可能因为内存不足已经销毁了,然后在用户操作下回到活跃状态了,那么异步拿到的数据可能是没有塞给UI控件的,一般都是在onResume时又异步获取一次数据,然后更新到UI控件上。
基于3.1对于LiveData数据更新本质的分析,如果我们使用LiveData的setValue/postValue,然后通过observe()分发进行监听,使用String/Int/CustomEvent(自定义的事件类,类似于EventBus)等数据做为事件分发。虽然这种方式能够避免内存泄漏,但是事件是粘性的,先发送事件,然后注册也会接收到该事件,这样的逻辑实际上并不是我们日常业务的事件逻辑。
google官方sample只处理一次的LiveData事件实现方案:
官方todoapp的Event实现
ps: 不得不说,老外的文章写得还是蛮清楚的,循序渐进,解释各种方案的问题,层层递进,对读者更好的理解有莫大帮助。
这个问题是因为postValue的实现逻辑导致的,如下是postValue的代码:
protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
    @SuppressWarnings("unchecked")
    @Override
    public void run() {
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        setValue((T) newValue);
    }
};
 
第一次postValue,postTask是true,mPendingData赋值为value,首次调用因为mPending值是NOT_SET,所以postTask为true, 会调用postToMainThread方法。
然后同步短时间内再次调用postValue,这时候因为mPostValueRunnable中的逻辑还未执行,所以mPendingData会赋值为新的value值,但是这次因为mPending不再是NOT_SET,而是第一次调用的值了,所以postTask为false,postValue方法直接return了。
然后在mPostValueRunnable.run方法被执行到时,mPendingData已经是最后一次调用postValue时传入的值了,所以mPostValueRunnable中调用的setValue方法,最终回调到Observer#onChanged的是最后一次postValue传入的值。


// 按钮点击是,连续多次执行postValue
simpleViewModel.liveData1.postValue("我是新数据0")
simpleViewModel.liveData1.postValue("我是新数据1")
simpleViewModel.liveData1.postValue("我是新数据2")
simpleViewModel.liveData1.postValue("我是新数据3")
// onChanged回调的结果只有最后一次
23:56:22.732  D  liveData1: onChanged newValue = 我是新数据3
// 如果给两次postValue之间加间隔呢?
simpleViewModel.viewModelScope.launch(Dispatchers.IO) {
    simpleViewModel.liveData1.postValue("我是新数据0")
    delay(10)
    simpleViewModel.liveData1.postValue("我是新数据1")
    delay(10)
    simpleViewModel.liveData1.postValue("我是新数据2")
    delay(10)
    simpleViewModel.liveData1.postValue("我是新数据3")
}
// 输出结果如下,就没有出现丢失数据的更新的情况了。并且尝试把间隔时间改成1ms,多次操作会出现可能丢失部分数据,
// 可能全部不丢失的,这里能说明上面关于postValue短时间内连续更新数据,可能只有最后一次分发给观察者的原因了。
// !!这里也能说明,使用LiveData实现事件分发,要也别注意异步分发事件可能丢事件的。
// 这里也说明了LiveData在异步数据流上是存在缺陷的,当然google又出了Flow组件专门用于处理数据流,待后续会分享其用法。
00:03:29.143  D  liveData1: onChanged newValue = 我是新数据0
00:03:29.199  D  liveData1: onChanged newValue = 我是新数据1
00:03:29.212  D  liveData1: onChanged newValue = 我是新数据2
00:03:29.232  D  liveData1: onChanged newValue = 我是新数据3
 
(1)数据粘性更新;
(2)异步更新数据的postValue可能丢失更新过程中的值,不适用于异步数据流的更新&展示。
比如:要实现进度的展示,用LiveData#postValue就可能出现进度变化过程丢一部分了,UI要的一些变化过程没了(貌似这个举例不妥~),作为事件总线分发事件可能丢失等情况;
【1】LiveData with SnackBar, Navigation and other events (the SingleLiveEvent case)