MVVM communication of Jetpack - principle analysis of LiveData

Posted by splatek on Mon, 06 Sep 2021 20:55:39 +0200

summary

In the last article, we introduced the basic use and principle analysis of ViewModel. Because ViewModel usually needs to be used in combination with inter component communication tools, the last article also talked about the scenario of the combination of ViewModel and LiveData. This time, we will analyze some principles of LiveData combined with the examples in the previous article.

Previous: MVVM implementation of Jetpack - use and source code analysis of ViewModel__ biz=Mzk0ODAyNjE3Nw==&mid=2247484048&idx=1&sn=50f8983b475deadb677efe4deee37cd2&chksm=c36cacbef41b25a8bdbde0999410d85dfa05ac07b19247adf4640c294f4e78615f01393763c9&token=2095993980&lang=zh_ CN#r

1. Use

Because this time we will mainly analyze some principles of LiveData, we will not create a Demo. To facilitate analysis, paste the last part of the code:

        // Note 1, registered observer
        mLiveData.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Toast.makeText(getApplicationContext(), "mag = " + s, Toast.LENGTH_SHORT).show();
            }
        });
       // Note 2, transmit data
       mLiveData.postValue(result);

2. Source code analysis

Now let's start with notes 1 and 2 above to analyze the registration and data transmission process of LiveData.

  • To register, first look at the registration process of the observer. The observe method in note 1 above:
    // LiveData.java
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // Note 3, get the Activity life cycle
            // If the component is in the DESTROYED state, registration is not allowed
            return;
        }
        LiveData.LifecycleBoundObserver wrapper = new LiveData.LifecycleBoundObserver(owner, observer);
        // Note 4: package the component and observer and store them in the linked list. If the object already exists, it will not be overwritten and existing will not be empty
        LiveData.ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        // Note 5: if the observer already exists, return and do not repeat the registration
        if (existing != null) {
            return;
        }
        // Note 6, save the observer in Lifecycle to complete the registration
        owner.getLifecycle().addObserver(wrapper);
    }
    //Note 7, putIfAbsent method
    public V putIfAbsent(@NonNull K key, @NonNull V v) {
        SafeIterableMap.Entry<K, V> entry = get(key);
        if (entry != null) {
            return entry.mValue;
        }
        put(key, v);
        return null;
    }

In note 3 above, we can see that LiveData judges the state of the observer component life cycle before registering the observer. If the observer lifecycle is already in   If the status is DESTROYED, it will be returned directly and will not be registered. Then, at the place of note 4, the wrapped observer object will be saved into the Map in the form of key value pairs.

If the object already exists, the overwrite operation is not performed, and the existing returned is not null. At this time, the registration method returns directly, and the registration will not be repeated. See note 7 for putIfAbsent storage method logic.

If the packaged observer object has not been saved and registered before, complete the registration in the Lifecycle of note 6 above. Now look at the observer wrapper class LifecycleBoundObserver in LiveData at note 4 above:

    // LiveData.java
    class LifecycleBoundObserver extends LiveData.ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;
        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(@NonNull LifecycleOwner source,
                                   @NonNull Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                // Note 8, when the component life cycle changes, the method is called back
                // When the component lifecycle state is DESTROYED, the observer is removed
                // In this way, no data will be received when the observer component is in the destroyed state
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }
        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }
        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }
    // Remove observer
    public void removeObserver(@NonNull final Observer<? super T> observer) {
        assertMainThread("removeObserver");
        LiveData.ObserverWrapper removed = mObservers.remove(observer);
        if (removed == null) {
            return;
        }
        removed.detachObserver();
        removed.activeStateChanged(false);
    }

The onStateChanged method in note 8 above calls back when the component life cycle changes. After judgment, the observer will be removed when the component lifecycle state is DESTROYED. In this way, no data will be received when the observer component is in the DESTROYED state.

According to the above analysis of the registration process, we briefly summarize the following two points for the LiveData life cycle:

(1) LiveData is not registered when the observer is destroyed

(2) LiveData has the life cycle awareness of components (through LifeCycle). When the component is destroyed, LiveData removes the observer to avoid memory leakage.

  • Next, go back to note 2 above and start with the LiveData.postValue(result) method to see the LiveData data data sending process:
    // LiveData.java
    public void postValue(T value) {
        super.postValue(value);
    }
    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        // Note 9: package the message to be sent and switch to the main thread to execute the setValue () method
        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;
            }
            // Note 10, the setValue () method is executed in the main thread
            setValue((T) newValue);
        }
    };

From the comments above, we can see that the postValue method finally switches to the main thread and executes the setValue method. Now let's look at the setValue method:

   // LiveData.java
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }
    void dispatchingValue(@Nullable LiveData.ObserverWrapper initiator) {
        ......
        for (Iterator<Map.Entry<Observer<? super T>, LiveData.ObserverWrapper>> iterator =
             mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
            //Note 11, traversing the observer
            considerNotify(iterator.next().getValue());
            if (mDispatchInvalidated) {
                break;
            }
        }
        ......
    }
    private void considerNotify(LiveData.ObserverWrapper observer) {
        // Note 12: the observer life cycle is not Active and is not sent
        // The Active state includes STARTED and RESUMED, that is, onStart() and onResume() methods corresponding to our component life cycle
        if (!observer.mActive) {
            return;
        }
         ......
        observer.mObserver.onChanged((T) mData);
    }

As we can see above, setValue will call the dispatchingValue(null) method to distribute events.

The dispatchingValue method will traverse all observers and then execute the considerNotify method. So will LiveData send data to all observers? See note 12 above. Before sending data, LiveData will judge the current life cycle state of the observer.

Only observers who are currently active will receive data, and   Active   States include STARTED and RESUMED, that is, onStart() and onResume() methods corresponding to our component life cycle.

This is the conclusion we need to know. The data of LiveData will be received only when the component lifecycle is in the Start or Resume state. In this way, the component does not need to judge its current state when receiving data display.

MVVM communication of Jetpack - principle analysis of LiveData? Mp.weixin.qq.com/s__ biz=Mzk0ODAyNjE3Nw==&mid=2247484095&idx=1&sn=93aa5f589e64868a529a3b7c3631d7bb&chksm=c36cac91f41b258742f77da614f6a3e401ce997b3aa02f093a0287b5aa050cff698a7da1c7bb&token=2095993980&lang=zh_ CN#rd

Topics: architecture LiveData