LiveData原理小探究

1,472 阅读4分钟

1.前言

LiveData是Android Jetpack中的重要组件,也是我们实现MVVM架构的一种方式。它提供了一种可观察的数据,让开发者能通过观测LiveData获取数据的变动。在LiveData中我们最常用的方法是,setValue和postValue,所以我打算已这两个函数为入口对LiveData进行探究。本文是看了 LiveData为何这么香,这些你都知道吗?之后写的。

2.setValue

@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

@MainThread这个注释表示setValue()需要在主线程中调用,函数内又使用assertMainThread断言来确保方法是运行在主线程的。mVersion这个属性表示了是用于对值 的新旧进行比较,后续还会用到。然后就是mData = value对值就行保存。接下来就进入了dispatchingValue()这个方法顾名思义就知道应该是对值进行分发。

void dispatchingValue(@Nullable ObserverWrapper initiator) {
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {
            considerNotify(initiator);
            initiator = null;
        } else {
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

这段代码中有两个标志属性:mDispatchingValuemDispatchInvalidated,这两个是用来判断当前这个值分发是否在进行,要是没有这两个属性,就有可能会导致新的值被旧的值覆盖。mDispatchingValue = true的时候表示值分发正在进行,如果传入的initiator(观察者)是空的话,就通知所有的观察者。如果在分发过程中有新的值传入的话mDispatchInvalidated就会为true,当前的for循环就会跳出,导致从头开始分发新的值。以上都是本人各人理解。(PS.我有一点不懂的是如果新方法进入的时候mDispatchInvalidated = true运行完之后刚刚好之前的函数运行到mDispatchInvalidated = false怎么办)。这个方法中通知各个观察者的方法是considerNotify,我们继续来看它的源码。

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);
}

这个方法我们先大体看一下,大概就是判断这个观察者是否是活跃状态,新更新的这个值是否比当前的值新(通过version比较),如果以上条件都满足就通知给观察者。这个方法里面有一个shouldBeActive的调用也很有意思,我们也可以看看它的源码。ctrl+左键点击发现这个函数是一个抽象函数,我们可以使用ctrl+alt+b点击ObserverWrapper这个抽象类就能看见它的实现类。分别是AlwaysActiveObserverLifecycleBoundObserver,我们先开比较简单的AlwaysActiveObserver,这个类目就能看出它的作用。

private class AlwaysActiveObserver extends ObserverWrapper {
    @Override
    boolean shouldBeActive() {
        return true;
    }
}

就是这个观察者会一直活跃。另一个LifecycleBoundObserver,顾名思义肯定是跟生命周期有关系,

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
    @Override
    boolean shouldBeActive() {
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }
}
    public enum State {
        DESTROYED,
        INITIALIZED,
        CREATED,
        STARTED,
        RESUMED;
        public boolean isAtLeast(@NonNull State state) {
            return compareTo(state) >= 0;
        }
    }

根据源码可以知道这个观测者只会在状态为STARTED和RESUMED的时候进行观察,这也让我们知道LiveData是如何自动绑定生命周期的。setValue的流程基本就到这里了,如果有什么缺漏或者错误,希望大家多多指出。

3.postValue

postValue没有对调用线程进行限制,所以所有线程中都可以调用postValue

protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {  //mPendingData!=NOT_SET
        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方法时,只有最后一次会生效,因为当postValue的任务正在进行时,mPendingData!=NOT_SET,这样就不会post新的任务,只有上一次post结束时,才会开始下一次,而此时mPendingData等于最后一次更新的值。再接下去就是调用setValue了,就是重复上面的过程。

4.小结

这算是第一次比较认真的去读官方的源码,我觉得官方源码的命名都特别规范,很多都能见名知意。确实很不错,我觉得这一部分代码中设计最好的就是dispatchingValue这一部分,通过两个标志位防止覆盖。要是让我来写,可能会复杂很多。