This article was first published on the wechat official account “Houchang Village Code Nong”.

preface

In the last article we looked at the basic usage of LiveData. We know that LiveData is an observable data holder with component lifecycle awareness, so how does it observe component lifecycle changes? The difference between LiveData and RxJava is that LiveData does not inform all observers. It only notifying observers who are in the Active state. If an observer is in the Active state, it will not be notified. And the other thing is, what’s happening inside of the MAP method in Translations? And so on, will be explained to you in this article.

1. How does LiveData observe component life cycle changes

The observer is registered by calling LiveData’s Observe method, which is shown below. frameworks/support/lifecycle/livedata-core/src/main/java/androidx/lifecycle/LiveData.java

 @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        // Return the view if the state of the observer is DESTROYED
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {/ / 1
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);/ / 2
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);/ / 3
        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);/ / 4
    }
Copy the code

The owner of an DESTROYED component is not allowed to be registered as the owner of an DESTROYED component. The owner of an DESTROYED component is not allowed to be registered as the owner of an DESTROYED component. The owner of an DESTROYED component is not allowed to be registered as the owner of an DESTROYED component.

If you are not yet aware of Lifecycle’s state, check out The Android Jetpack Architecture Components iii article which will guide you through Lifecycle (principles). A new LifecycleBoundObserver wrapper class is created in note 2, passing in the owner and observer. Note 3 stores the observer and LifecycleBoundObserver to SafeIterableMap< observer
, ObserverWrapper>mObservers, the putIfAbsent method is different from the PUT method. If the value corresponding to the passed key already exists, the putIfAbsent method returns the existing value without replacement. If not, add the key and value and return NULL. If it is null, LifecycleBoundObserver will be added to Lifecycle at comment 4 to complete the registration so that when we call the Observe method in LiveData, it is actually adding an observer inside Of LiveData to complete Lifecycle. This naturally gives LiveData the ability to observe changes in the lifecycle of components.

2.LiveData callback to the observe method

LifecycleBoundObservers is the inner class of LiveData, as shown below. frameworks/support/lifecycle/livedata-core/src/main/java/androidx/lifecycle/LiveData.java

 class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
        @NonNull final LifecycleOwner mOwner;

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

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

        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);/ / 1
                return;
            }
            activeStateChanged(shouldBeActive());/ / 2
        }

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

        @Override
        void detachObserver(a) {
            mOwner.getLifecycle().removeObserver(this); }}Copy the code

LifecycleBoundObserver inherits from the ObserverWrapper class and overwrites the shouldBeActive method to determine if the incoming component’s state is Active, which includes both STARTED and RESUMED.

LifecycleBoundObserver implements the GenericLifecycleObserver interface. The onStateChanged method is called when the component state changes. When the component is in an DESTROYED state, the onStateChanged method is called. The removeObserver method in comment 1 is called to remove the observer. This solves the question at the beginning of this article as to why an observer (component) will not be notified when it is in the DESTROYED state.

The activeStateChange method at comment 2 is then called, as shown below.

frameworks/support/lifecycle/livedata-core/src/main/java/androidx/lifecycle/LiveData.java

  private abstract class ObserverWrapper {
        final Observer<? super T> mObserver;
        boolean mActive;
        int mLastVersion = START_VERSION;

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

        abstract boolean shouldBeActive(a);

        boolean isAttachedTo(LifecycleOwner owner) {
            return false;
        }

        void detachObserver(a) {}void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            if (wasInactive && mActive) {
                onActive();
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive();
            }
            if (mActive) {
                dispatchingValue(this);/ / 1}}}Copy the code

The activeStateChanged method, defined in the abstract ObserverWrapper class of the Observer, is based on the Active state and the number of Active components, To call back to the onActive and onInactive methods that are used to extend the LiveData object. Note 1, if the status is Active, calls the dispatchingValue method and passes itself in.

  private void dispatchingValue(@Nullable ObserverWrapper initiator) {
        // The distribution is underway
        if (mDispatchingValue) {
            // The distribution is invalid
            mDispatchInvalidated = true;/ / 1
            return;
        }
        mDispatchingValue = true;
        do {
            // Distribution valid
            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);
        // The tag is not in the distribution state
        mDispatchingValue = false;
    }
Copy the code

MDispatchingValue is used to indicate whether the current dispatchingvalue is in the distribution state. If the current dispatchingvalue is in the distribution state, then note 1 indicates that the current dispatchingvalue is invalid and returns directly. If ObserverWrapper is null, as we’ll see in Section 3, then we’ll call the notify method as shown below.

    private void considerNotify(ObserverWrapper observer) {
        if(! observer.mActive) {/ / 1
            return;
        }
        if(! observer.shouldBeActive()) { observer.activeStateChanged(false);/ / 2
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //noinspection unchecked
        observer.mObserver.onChanged((T) mData);/ / 3
    }
    
Copy the code

If the mActive value of ObserverWrapper is not true, return the app by notice. In note 2, if the state of the component corresponding to the current observer is not Active, the activeStateChanged method is called again with false and the method internally again evaluates whether the onActive and onInactive method callbacks are executed. If all the criteria are met, the onChanged method of the Observer is called, which is the callback to the observe method that uses LiveData.

3. PostValue /setValue analysis

When the observe method of MutableLiveData is called, the data needs to be updated through the postValue/setValue method. frameworks/support/lifecycle/livedata-core/src/main/java/androidx/lifecycle/LiveData.java

.private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run(a) {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            //noinspection unchecked
            setValue((T) newValue);/ / 1}}; .protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if(! postTask) {return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);/ / 2
    }
    
    @MainThread / / 3
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }
Copy the code

The postValue/setValue methods are both defined in LiveData, and according to notes 1 and 2, the postValue method is actually switched to the main thread to call the setValue method. Note 3 states that the setValue method runs on the main thread and internally calls the dispatchingValue method described in Section 2 when the ObserverWrapper parameter of the dispatchingValue method is null. From this we know that both LiveData’s Observe method and LiveData’s postValue/setValue method call the dispatchingValue method.

You could do a double doubling or a double doubling or a double doubling or a double doubling or a double doubling or a map

In addition to the above of the commonly used method, but also may use to Transformations. The map and Transformations. SwitchMap method, here to Transformations. The map as an example. This method is used to change the values stored in the LiveData object before it is distributed to observers, as shown in the code below. frameworks/support/lifecycle/livedata/src/main/java/androidx/lifecycle/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<>();/ / 1
        result.addSource(source, new Observer<X>() {
            @Override
            public void onChanged(@Nullable X x) { result.setValue(mapFunction.apply(x)); }});return result;
    }
Copy the code

The annotated MediatorLiveData method is created at comment 1, and then its addSource method is called: support/lifecycle/livedata/src/main/java/androidx/lifecycle/MediatorLiveData.java

* /@MainThread
    public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
        Source<S> e = new Source<>(source, onChanged);/ / 1Source<? > existing = mSources.putIfAbsent(source, e);if(existing ! =null&& existing.mObserver ! = onChanged) {throw new IllegalArgumentException(
                    "This source was already added with the different observer");
        }
        if(existing ! =null) {
            return;
        }
        if (hasActiveObservers()) {
            e.plug();/ / 2}}Copy the code

Note 1 encapsulates the passed LiveData and onChanged into the Source class, and note 2 calls the Plug method of Source:

 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, final Observer<? super V> observer) {
            mLiveData = liveData;
            mObserver = observer;
        }

        void plug(a) {
            mLiveData.observeForever(this);/ / 1
        }

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

        @Override
        public void onChanged(@Nullable V v) {
            if(mVersion ! = mLiveData.getVersion()) { mVersion = mLiveData.getVersion(); mObserver.onChanged(v);/ / 2}}}Copy the code

You can see in comment 2 that the callbacks of the Observer passed in to the doubling. Map method are processed here. In note 1, Source’s plug method calls LiveData’s observeForever method. How is this different from section 2? Let’s go down a little bit. frameworks/support/lifecycle/livedata-core/src/main/java/androidx/lifecycle/LiveData.java

    @MainThread
    public void observeForever(@NonNull Observer<? super T> observer) {
        assertMainThread("observeForever");
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);/ / 1
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if(existing ! =null && existing instanceof LiveData.LifecycleBoundObserver) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if(existing ! =null) {
            return;
        }
        wrapper.activeStateChanged(true);
    }

Copy the code

Wrap the Observer with AlwaysActiveObserver, then call the AlwaysActiveObserver’s activeStateChanged method, What is actually called internally is the activeStateChanged method of ObserverWrapper, which is analyzed in section 2 and won’t be repeated here. Look at how the AlwaysActiveObserver class is defined. frameworks/support/lifecycle/livedata-core/src/main/java/androidx/lifecycle/LiveData.java

   private class AlwaysActiveObserver extends ObserverWrapper {
        AlwaysActiveObserver(Observer<? super T> observer) {
            super(observer);
        }
        @Override
        boolean shouldBeActive(a) {
            return true; }}Copy the code

AlwaysActiveObserver is an inner class of LiveData. It inherits from ObserverWrapper. The difference between AlwaysActiveObserver and ObserverWrapper is that It’s always Active.

5. LiveData association class

The following IS a UML diagram of the LiveData association classes. After you understand this diagram, go back and re-read this article for more information.

For more, check out my independent blog Body of Knowledge: liuwangshu.cn/system/


Here we share not only big front-end, Android, Java and other technologies, but also programmer growth articles.