Analysis of LiveData

LiveData is an important part of Jetpack and plays a core role in the MVVM architecture.
But let's ignore its function in the whole architecture for the time being, but focus on its essence - the essence of LiveData is an observer, that is, Observable.

overview

A simple Observable looks like this:

public class ConcreteObservable implements IObservable {
    
    
	Vector<IObserver> vector = new Vector();

	@Override
	public void attach(IObserver observer) {
    
    
		this.vector.addElement(observer);
	}

	@Override
	public void detach(IObserver observer) {
    
    
		this.vector.removeElement(observer);
	}

	@Override
	public void submit(String content) {
    
    
		Iterator var2 = this.vector.iterator();

		while(var2.hasNext()) {
    
    
			IObserver observer = (IObserver)var2.next();
			observer.update(content);
		}
	}
}

Three methods: add observer, remove observer, notify observer.

Next, let's take a look at the source code of LiveData to find out the corresponding method.

add observer

The first is to add the observer:

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

It's easy to find.

  1. Look at the parameters first, needless to say the second parameter, the first parameter LifecycleOwner is an interface that can perceive the life cycle, and the Activity/Fragment of the new version (theoretically after 26.1.0, including androidx) implements this interface internally;
  2. Looking at the method body again, the first line is asserting that it is currently the main thread, which means that this method can only be called on the main thread;
  3. The second line judges that if the life cycle of the current component is DESTROYED, that is, the state of being destroyed, it will not take effect;
  4. The next step is to wrap the incoming observer layer by layer, and add it to the observer collection, and judge whether there is a situation of repeated addition;
  5. Finally, the life cycle manager also added this packaged observer;

remove observer

Next, look at the removal logic:

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

    @MainThread
    public void removeObserver(@NonNull final Observer<? super T> observer) {
    
    
        assertMainThread("removeObserver");
        ObserverWrapper removed = mObservers.remove(observer);
        if (removed == null) {
    
    
            return;
        }
        removed.detachObserver();
        removed.activeStateChanged(false);
    }

It is also necessary to determine whether it is in the main thread, and then remove it from the observer set mObservers. Finally, if the observer is not empty, the activeStateChanged method will be called once;
activeStateChanged is the trigger of the observer.

notify observer

ObserverWrapper is used for adding and removing observers above, so start here and take a look at ObserverWrapper :

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

        boolean isAttachedTo(LifecycleOwner owner) {
    
    
            return false;
        }

        void detachObserver() {
    
    
        }

        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) {
    
    //1
                onActive();
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
    
    //2
                onInactive();
            }
            if (mActive) {
    
    //3
                dispatchingValue(this);
            }
        }
    }

You can see that its construction method wraps the most primitive observer interface:

public interface Observer<T> {
    
    
    void onChanged(T t);
}

Then let's pay attention to the activeStateChanged method, which is mainly used to change the active state of the current Observer ;
you can see that the incoming value must be different from the active state of the current Observer to continue the subsequent logic;
then judge if the current Observer is in the active state (mActive is true), the number of Observers held by the current LiveData will be increased by 1, otherwise it will be decreased by 1;
finally there are 3 judgments:

  1. If there is no Observer at this stage and mActive is true, newActive is true and mActive is false, and mActive will change from false to true, it means that this LiveData has changed from a state without observers to a state with observers, then Call the onActive method, onActive is an empty method, which belongs to LiveData and can be overridden
  2. When all Observers are removed and mActive is false, newActive is false and mActive is true, and when mActive changes from true to false, it means that the last observer of this LiveData, the current Observer, is also removed, then Call the onInactive method, which is an empty method like onActive
  3. mActive is true, the current Observer is active, to trigger the notification operation

The dispatchingValue method is the notification method of LiveData, which can be seen from the setValue method of LiveData :

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

It must also be called on the main thread, and every time the data is updated, the "version" of the current LiveData, that is, mVersion, will be cumulatively updated once, and then dispatchingValue will be called; indicating that dispatchingValue is likely to be the starting point for notifying
the Observer ;

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

There are two tag values, mDispatchingValue and mDispatchInvalidated, these two tag values ​​only appear here, and their function is roughly for anti-shake; then the considerNotify
method will be called , if the incoming Observer is not empty, the Observer will be notified directly, if If it is empty, all Observers held by the current LiveData will be notified. Continue to focus on the considerNotify method:

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

Still analyze step by step:

  1. If the Observer is inactive, return directly without any operation
  2. If the life cycle of the Observer's current component is before onStart, it will call the activeStateChanged method and pass in true; since the first step has been judged, mActive must be true in the activeStateChanged method, then the mActive state of this Observer will be changed by true becomes false, that is, the Observer will become inactive and call the onInactive method
  3. Under normal circumstances, this condition is not true, mVersion will be accumulated first, and Observer will copy the value of mVersion
  4. If none of the above conditions are true, then start notifying the real observer mObserver

So far, the basic process has gone through.
Draw a simple timing diagram like this:
insert image description here

other extensions

LifecycleBoundObserver

In the method of adding observer observe, we have seen LifecycleBoundObserver, so let's take a look at LifecycleBoundObserver :

    class LifecycleBoundObserver extends 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) {
    
    
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }

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

        @Override
        void detachObserver() {
    
    
            mOwner.getLifecycle().removeObserver(this);
        }
    }

Just look at the onStateChanged method, which is the logic called by the Observer party after being notified. You can see that the state of the life cycle is judged first. If it has been destroyed, then removeObserver will be called to remove the incoming Observer, otherwise continue to call activeStateChanged;
first look at what activeStateChanged does. Here, the Boolean value obtained by shouldBeActive() is passed in.
This Boolean value represents whether the life cycle has at least reached the level of onStart , that is, if the life cycle of the component where the Observer is located is still in OnStart Before, then the incoming is false, otherwise true;
So where is this onStateChanged method called?
In fact, this method is provided by the LifecycleEventObserver interface:

public interface LifecycleEventObserver extends LifecycleObserver {
    
    
    void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);
}

The last line in LiveData's observe method

    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    
    
		//...
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
		//...
        owner.getLifecycle().addObserver(wrapper);
    }

, it is added to the life cycle awareness, and its implementation method is in the LifecycleRegistry class:

    @Override
    public void addObserver(@NonNull LifecycleObserver observer) {
    
    
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
		//...
        State targetState = calculateTargetState(observer);
        mAddingObserverCounter++;
        while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
    
    
            pushParentState(statefulObserver.mState);
            statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
            //...
        }
    }

You can see that this Observer is packaged into another form of ObserverWithState here:

    static class ObserverWithState {
    
    
        State mState;
        LifecycleEventObserver mLifecycleObserver;

        ObserverWithState(LifecycleObserver observer, State initialState) {
    
    
            mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
            mState = initialState;
        }

        void dispatchEvent(LifecycleOwner owner, Event event) {
    
    
            State newState = getStateAfter(event);
            mState = min(mState, newState);
            mLifecycleObserver.onStateChanged(owner, event);
            mState = newState;
        }
    }

As the name implies, it is an Observer with a lifecycle state, and the dispatchEvent method will cause state changes and trigger operations, which also calls back the onStateChanged in the LifecycleBoundObserver; then when is the timing to
call the dispatchEvent method?
related to the lifecycle state.

    public enum State {
    
    
        DESTROYED,
        INITIALIZED,
        CREATED,
        STARTED,
        RESUMED;
    }

When the Observer is added for the first time, the Observer status is assigned as INITIALIZED, and there will be a comparison judgment later:

statefulObserver.mState.compareTo(targetState) < 0

This targetState can be understood as the lifecycle state of the component where the Observer is located. As long as the lifecycle state of the wrapped Observer is before the targetState, dispatchEvent will be called once.
When adding Observer for the first time, this life cycle is INITIALIZED. In general, we will add Observer at least after component onCreate or after, that is, the targetState is at least after CREATED, so INITIALIZED<CREATED is established;

        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;

So in theory the Observer will trigger once when it is first added .
This is the biggest difference between LiveData and the traditional observer mode, which is highly bound to the life cycle.

postValue

In addition to the setValue method that can only be run on the main thread, LiveData also provides an unlimited postValue method:

    static final Object NOT_SET = new Object();
    volatile Object mPendingData = NOT_SET;
    final Object mDataLock = new Object();

    protected void postValue(T value) {
    
    
        boolean postTask;
        synchronized (mDataLock) {
    
    
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
    
    
            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);
        }
    };

It is easy to see that the postValue method will eventually call the setValue method, but the ArchTaskExecutor is used to switch it to the main thread;

public class ArchTaskExecutor extends TaskExecutor {
    
    
    @NonNull
    private TaskExecutor mDelegate;

    @NonNull
    private TaskExecutor mDefaultTaskExecutor;
    
    private ArchTaskExecutor() {
    
    
        mDefaultTaskExecutor = new DefaultTaskExecutor();
        mDelegate = mDefaultTaskExecutor;
    }

    @Override
    public void executeOnDiskIO(Runnable runnable) {
    
    
        mDelegate.executeOnDiskIO(runnable);
    }

    @Override
    public void postToMainThread(Runnable runnable) {
    
    
        mDelegate.postToMainThread(runnable);
    }
}

ArchTaskExecutor's postToMainThread is actually the DefaultTaskExecutor used,

public class DefaultTaskExecutor extends TaskExecutor{
    
    
	    @Override
    public void postToMainThread(Runnable runnable) {
    
    
        if (mMainHandler == null) {
    
    
            synchronized (mLock) {
    
    
                if (mMainHandler == null) {
    
    
                    mMainHandler = createAsync(Looper.getMainLooper());
                }
            }
        }
        //noinspection ConstantConditions
        mMainHandler.post(runnable);
    }
}

Needless to say, the DefaultTaskExecutor is finally executed by the main thread Handler.

observeForever

What we have seen before is the observe method, which can only add Observers related to the life cycle, and LiveData also provides a method to add Observers that are not related to the life cycle:

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

See this AlwaysActiveObserver wrapper class name to understand, this is an "always active" Observer, which gets rid of the influence of the life cycle:

    private class AlwaysActiveObserver extends ObserverWrapper {
    
    

        AlwaysActiveObserver(Observer<? super T> observer) {
    
    
            super(observer);
        }

        @Override
        boolean shouldBeActive() {
    
    
            return true;
        }
    }

This is the same as the traditional observer mode, which is a kind of compatibility.

Guess you like

Origin blog.csdn.net/ifmylove2011/article/details/116520010