1. Introduction

LiveData is an important component in Android Jetpack and one of the ways we implement the MVVM architecture. It provides an observable data that allows developers to look at LiveData and see changes in the data. The most common methods we use in LiveData are setValue and postValue, so I’m going to explore LiveData using these two functions as entry points. This article is to see why LiveData so fragrant, these you all know? I wrote it later.

2.setValue

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

The @mainthread annotation indicates that setValue() needs to be called on the MainThread, and the assertMainThread assertion is used within the function to ensure that the method runs on the MainThread. The mVersion attribute is used to compare old and new values and will be used later. And then mData = value and just save the value. The next step is to enter dispatchingValue() which, as the name implies, is supposed to distribute values.

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;
}
Copy the code

There are two flag properties in this code: mDispatchingValue and mDispatchInvalidated, which are used to determine whether the current value distribution is in progress. Without these properties, it is possible that the new value may be overwritten by the old value. MDispatchingValue = true indicates that value distribution is in progress and notifies all observers if the incoming initiator is null. If a new value is passed in the distribution process mDispatchInvalidated will be true, and the current for loop will jump out, causing the new value to be distributed from scratch. All above are my understanding. (PS. What I don’t understand is if the new method enters with the mDispatchInvalidated = true and after the function is validated with the mDispatchInvalidated = false). The method in this method that tells each observer is called Notice, so let’s go back to the source code for this.

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);
}
Copy the code

This method is basically to determine whether the observer is active, whether the newly updated value is newer than the current value (by version comparison), and notify the observer if all of the above conditions are met. It’s also interesting that this method has a shouldBeActive call in it, and we can look at the source code for that as well. CTRL + left click to discover that this function is an abstract function. We can use CTRL + Alt + B to click on the abstract ObserverWrapper class and see its implementation class. They are AlwaysActiveObserver and LifecycleBoundObserver. Let’s start with the simpler AlwaysActiveObserver, which can be seen in this category.

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

This observer is going to stay active. The other LifecycleBoundObserver, as the name implies, is certainly related to the lifecycle,

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

From the source code we know that this observer will only observe when the state is STARTED and RESUMED, which gives us an idea of how LiveData automatically binds to the life cycle. That’s pretty much the end of the setValue process, so if there are any gaps or errors, I’d like you to point them out.

3.postValue

PostValue has no restrictions on the calling thread, so postValue can be called from any thread

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(a) {
            Object newValue;
            synchronized(mDataLock) { newValue = mPendingData; mPendingData = NOT_SET; } setValue((T) newValue); }};Copy the code

When postValue is called multiple times, only the last time will take effect, because mPendingData! =NOT_SET, so that no new task is posted, and the next one will only start when the last post is finished, when the mPendingData is equal to the last updated value. The next step is to call setValue, which is to repeat the above procedure.

4. Summary

This is the first time more seriously to read the official source code, I think the official source code are special specifications, many can see the meaning. It’s really nice. I think the best design in this part of the code is the dispatchingValue part, with two flags to prevent overwriting. If I were to write it, it would be a lot more complicated.