This is the 22nd day of my participation in the More text Challenge. For details, see more text Challenge

Source code analysis

LiveData#observe

private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
            new SafeIterableMap<>();

	@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            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);
    }

Copy the code

When we call observer(), we pass two arguments. The first is an instance of the LifecycleOwner interface, which our inherited AppCompatActivity parent already implements, so we pass this. The second parameter, Observer, is the callback we observe.

Owner.getlifecycle ().getCurrentState() ¶ If it is destroyed, return it (since we said that only active components will be updated).

The owner and observer are then constructed as LifecycleBoundObserver instances, an inner class that contains a series of operations related to state transitions, which will be examined in more detail later.

The observer and wrapper are then placed in the Map cache, and an exception is thrown if the observer cache already exists and is bound to another LifecycleOwner. If the cache already exists, it is ignored.

That is, an Observer instance can only be bound to one LifecycleOwner, while an owner can be bound to multiple Observer instances;

Finally, call the addObserver method to bind the LifecycleBoundObserver instance to the LifecycleOwner. And addObserver is an implementation that calls the LifecycleRegistry class.

When the owner (Activity or fragment) life cycle changes, the LifecycleBoundObserver onStateChanged method is called, The onStateChanged method in turn calls back to the Observer’s onChange method.

LifecycleBoundObserver

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);
                return;
            }
            activeStateChanged(shouldBeActive());
        }

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

        @Override
        void detachObserver(a) {
            mOwner.getLifecycle().removeObserver(this); }}Copy the code
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 the old and new states are the same, ignore
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;    
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            // The number of active observers ranges from 0 to 1
            if (wasInactive && mActive) {
                onActive();// Empty implementation, usually let subclasses override
            }
            // The number of active observers ranges from 1 to 0
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive();// Empty implementation, usually let subclasses override
            }
            // Active state, which sends the LiveData value to the observer
            if (mActive) {
                dispatchingValue(this); }}}Copy the code

Take a look at LifecycleBoundObserver, which inherits ObserverWrapper and implements the GenericLifecycleObserver interface. The GenericLifecycleObserver interface implements the LifecycleObserver interface. It wraps our external observer, somewhat similar to the proxy pattern. We can review the Lifecycle component. The onStateChanged() method is used to call back when the lifecycle of a component (Fragment, Activity) changes.

GenericLifecycleObserver#onStateChanged

When the Activity callback cycle changes, it will call back onStateChanged, first checking whether mowner.getLifecycle ().getCurrentState() has destroyed, if. Has destroyed, directly remove the observer. This is why we do not need to manually remove the observer.

If the state is not destroyed, the activeStateChanged method is called with the value returned by shouldBeActive(). When lifecycle’s state is STARTED or RESUMED, the shouldBeActive method returns true, indicating activation.

In the activeStateChanged method, when newActive is true and not equal to the last value, the LiveData mActiveCount count will be increased. As you can see, onActive fires when mActiveCount is 1, and onInactive only fires when mActiveCount is 0. That is, when the onActive method is called, the active observer is exactly 1. When the onInactive method is called, none of the observers are active.

When mActive is true, the dispatchingValue method is activated.

@SuppressWarnings("WeakerAccess") /* synthetic access */
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        // If it is being processed, return directly
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            // If the initiator is not null, call the notice method
            if(initiator ! =null) {
                considerNotify(initiator);
                initiator = null;
            } else { // When null, all obsever are traversed and distribution is made
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break; }}}}while (mDispatchInvalidated);
         // Set to false when distribution is complete
        mDispatchingValue = false;
    }
Copy the code

MDispatchingValue and mDispatchInvalidated can only be used in the dispatchingValue method. Obviously, these two variables are used to prevent duplicate distribution of the same content. When the initiator is not null, only the current observer is processed. When the initiator is null, all obsever are traversed and distributed

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;
        //noinspection unchecked
        observer.mObserver.onChanged((T) mData);
    }
Copy the code
  1. If the state is not active, return it directly. This is why we do not call back the onChange method of the observer when our Activity is in onPause, onStop, or onDestroy.
  2. Determines whether the data is up to date. If it is, return without processing
  3. The data is not up to date, call back to the mobServer.onchanged method. And pass the mData

LiveData#setValue

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

In the setValue method, first, the assertion is the main thread, followed by mVersion + 1; The value is assigned to mData and then the dispatchingValue method is called. DispatchingValue is passed null to indicate that all observers are processed.

If the activity we are attached to is in onPause or onStop, we will not call the onChange method of the observer, although the dispatchingValue method is returned directly. But when the attached activity comes back to the foreground, it triggers the LifecycleBoundObserver onStateChange method, which in turn calls the dispatchingValue method. In this method, Because mLastVersion < mVersion. So the onChange method of obsever is called back, and this is where LiveData is clever

Similarly, if you call the setValue method of LiveData multiple times while the activity is in the background, you will only end up calling back the onChange method of the LiveData Observer once.

LiveData#postValue

protected void postValue(T value) {
        boolean postTask;
    	/ / lock
        synchronized (mDataLock) {
             // No one is currently working on the POST task
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if(! postTask) {return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run(a) {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                 // Set mPendingData to NOT_SET after processing
                mPendingData = NOT_SET;
            }
            //noinspection uncheckedsetValue((T) newValue); }};Copy the code
  1. First, use the synchronization mechanism, postTask = mPendingData == NOT_SET whether someone is working on the task. True, no one is working on the task, false, someone is working on the task, if someone is working on the task, just return
  2. Call AppToolkitTaskExecutor. GetInstance (). The postToMainThread to the main thread mPostValueRunnable missions.

LiveData#observeForever

@MainThread
    public void observeForever(@NonNull Observer<? super T> observer) {
        assertMainThread("observeForever");
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        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

Because AlwaysActiveObserver does not implement the GenericLifecycleObserver method interface, the onStateChange method is not called back when the Activity O lifecycle changes. The observer will not be removed voluntarily. Because our obsever is removed depends on calling back to the onStateChange method of the GenericLifecycleObserver when the Activity lifecycle changes.

Sequence diagram

Borrow a picture from the Internet

There are three main timings involved in LiveData:

  • Add the observer(second parameter in the observer() method) to the Fragment/Activity via liveData.observer ().
  • Remove observers or notify observers to update data as the Fragment/Activity lifecycle changes.
  • When the setValue() and postValue() methods of LiveData are called, the observer is notified to update the data.

todo

NetworkBoundResource

Juejin. Cn/post / 684490…

permissions

Juejin. Cn/post / 5 c106a…

conclusion

LiveData advantages

1. Ensure that the UI conforms to the data state. LiveData notifies the Observer when the lifecycle state changes. You can incorporate code that updates the UI into these Observer objects. Instead of considering the timing of the data changes, the Observer updates the UI every time the data changes.

2. No memory leak Observer will bind objects with a lifetime and clean up after the bound object is destroyed.

If the Observer life cycle is inactive, such as an Activity on the back stack, it will not be notified of any LiveData events.

There is no need to manually process the life cycle. UI components only need to observe the relevant data. There is no need to manually stop or resume the observation. LiveData manages these things automatically because, as it observes, it is aware of the lifecycle changes of the corresponding components.

5. Keep Data Up to date If an object becomes inactive in its lifetime, it will receive the latest data when it becomes active again. For example, a background Activity receives the latest data immediately after returning to the foreground.

6. Respond to Configuration Changes Properly If an Activity or Fragment is recreated as a result of a configuration change, such as device rotation, it immediately receives the latest available data.

7. Sharing resources you can use the singleton pattern to extend LiveData objects and wrap them as system services for sharing across applications. Once a LiveData object is connected to a system service, any Observer that needs the resource simply observes the LiveData object.

Use the LiveData object step

  • LiveDataBased on the observer pattern implementation, and andLifecycleOwnerTo bind, andLifecycleOwnerHas beenFragmentAnd the Activity implementation, so it can sense the lifecycle; LifecycleOwner is not active at the current time (for exampleonPasue(),onStop()), LiveData does not call backobserve()Because it doesn’t make sense.
  • At the same timeLiveDataOnly inLifecycleOwnerIn aActiveIf the data change occurs in the inactive state, the data will change, but no notification is sent, etcownerReturn to the active state and send the notification.
  • LiveDataWill be removed in DESTROYEDObserver, unsubscribe without memory leaks
  • postValueIn an asynchronous thread,setValueIn the main thread
  • ifLiveDataHas not beenobserve()Then you call the postValue(…) of this LiveData /value=… , it isIt doesn’t make any difference

reference

Official documentation :LiveData Overview

Jetpack source code parsing – Use and how LiveData works

Android LiveData source code anatomy

Android source code parsing -LiveData