preface

According to Jepack official documentation:

LiveData is an observable data store class. Unlike regular observable classes, LiveData has lifecycle awareness, meaning that it follows the lifecycle of other application components such as activities, fragments, or services. This awareness ensures that LiveData updates only application component observers that are in an active lifecycle state.

If an Observer (represented by an Observer class) is in a STARTED or RESUMED state during its lifecycle, LiveData considers the Observer to be active. LiveData only notifies active observers of updates. Inactive observers registered to observe LiveData objects do not receive notification of changes.

You can register observers that are paired with objects that implement the LifecycleOwner interface. With this relationship Lifecycle objects can be removed when the state of the corresponding Lifecycle object changes to DESTROYED. This is especially useful for activities and fragments because they can safely observe LiveData objects without fear of leakage (the system unsubscribe them immediately when the Activity and Fragment’s life cycle is destroyed).

We now know that LiveData enables data updates to be sensed by the Observer in observer mode, and this perception only occurs in the active lifecycle state of the LifecycleOwner.

So how does it sense life cycle changes? Do I need to cancel my registration? Will subscribed observers receive the same value when setting the same value? Also, what are sticky events, and how do you prevent data flooding? Take a look at the source code implementation with these questions in mind.

How does LiveData sense life cycle awareness

When using liveData. observe subscribers, this is called

edPacketVm.grabRedPacketLiveData.observe(this, Observer {
            .....
        })
Copy the code

Let’s start with the Livedata.observer method:

### LiveData    
@MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // DESTROYED in the lifecycle, do not subscribe
            return;
        }
  	// Wrap the object with LifecycleBoundObserver
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
  	//LifecycleBoundObserver is a subclass or implementation of ObserverWrapper
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
  	You cannot add the same Observer to two different lifecycle objects.
        if(existing ! =null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if(existing ! =null) {
            return;
        }
  	// Have the ability to perceive the life cycle
        owner.getLifecycle().addObserver(wrapper);  
    }
Copy the code

LifecycleOwner is DESTROYED; return. Components in the DESTROYED state are not allowed to be registered.

The LifecycleBoundObserver class is then created, wrapped around the Observer, and the putIfAbsent method is called to store the owner and Obseerver one-key value pairs into the mObservers.

Finally, this will be added to Lifecycle via owner.getlifecycle ().addobServer so that when we call the Observer method, Lifecycle observer will actually be added inside LiveData. This gives LiveData the ability to observe the life cycle of components.

Observer event callback

Let’s look at the key class LifecycleBoundObserver. How does the callback work?

// The observer implementation
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;
  			boolean mActive;
        int mLastVersion = START_VERSION;

	LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }
          
       @Override
        boolean shouldBeActive(a) {
          // Determine whether the current incoming component is Active
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }
          
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
          // Get the life cycle
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            if (currentState == DESTROYED) {
              // If it is destroyed, call livedata.removeObserver to remove it
                removeObserver(mObserver);
                return;
            }
            Lifecycle.State prevState = null;
          // Two state changes are also called back
            while(prevState ! = currentState) { prevState = currentState;// See belowactiveStateChanged(shouldBeActive()); currentState = mOwner.getLifecycle().getCurrentState(); }}@Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

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

LifecycleBoundObserver implements the LifecycleEventObserver method, which implements the lifecycle state callback in the onStateChanged method. Removes the observer when the state is in a DESTROYED state. This is why Livedata does not need to be unregistered. Therefore, an observer is not notified when they are in a DESTROYED state.

Take a look at the implementation of activeStateChanged:

 private abstract class ObserverWrapper {
        final Observer<? super T> mObserver;
        boolean mActive;
        intmLastVersion = START_VERSION; .void activeStateChanged(boolean newActive) {
          // If mActive is not assigned, the default value is false
        // When we just called activeStateChanged, the value passed in is true as returned by shouldBeActive()
            if (newActive == mActive) {
              // If the active state has not changed, it will not be processed.
                return;
            }
          
            mActive = newActive;
          // Extend Livedata based on Active state and the number of components in Active state
            changeActiveCounter(mActive ? 1 : -1);
            if (mActive) {
              // When the observer becomes active, data is distributed
                dispatchingValue(this); }}}// Implement it
 void changeActiveCounter(int change) {
        int previousActiveCount = mActiveCount;
        mActiveCount += change;
        if (mChangingActiveState) {
            return;
        }
        mChangingActiveState = true;
        try {
            while(previousActiveCount ! = mActiveCount) {boolean needToCallActive = previousActiveCount == 0 && mActiveCount > 0;
                boolean needToCallInactive = previousActiveCount > 0 && mActiveCount == 0;
                previousActiveCount = mActiveCount;
                if (needToCallActive) {
                  // The number of active observers changes from 0 to 1
                    onActive();
                } else if (needToCallInactive) {
                  // The number of active observers changed from 1 to 0onInactive(); }}}finally {
            mChangingActiveState = false; }}Copy the code

The activityStateChange method resides in ObserverWrapper and is an inner class to LiveData. Internally, onActive and onInactive, respectively, are called based on the number of Active components in A, which belong to the callback methods used by the Livedata extension.

When the observer is active, the dispatchingValue method is called for data distribution.

 void dispatchingValue(@Nullable ObserverWrapper initiator) {
   // If it is being distributed, the distribution is invalid
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
    // The tag is being distributed
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if(initiator ! =null) {
                considerNotify(initiator);
                initiator = null;
            } else {
              //observerWrapper is empty, traversing notifies all observers
                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

This does not continue distribution if it is currently being distributed. When you step down, the notice method is called regardless of whether ObserverWrapper is null. Let’s look at the notice method.

public LiveData(a) {
        mData = NOT_SET;
  			// Initial assignment
        mVersion = START_VERSION;
    }    

private void considerNotify(ObserverWrapper observer) {
        if(! observer.mActive) {return;
        }
        
      // Judge is active
  		// If the owner corresponding to the current Observer is inactive, the activeStateChanged method is called again and false is passed, which is evaluated internally again
        if(! observer.shouldBeActive()) { observer.activeStateChanged(false);
            return;
        }
      
      //mLastVersion does not have an initial value
      //mVersion +1 each time the setValue method is called
      / / vesion of judgment
        if (observer.mLastVersion >= mVersion) {
            return;
        }
      //mLastVersion is only assigned here
        observer.mLastVersion = mVersion;
      // This finally calls the onChanged method of the Observer passed in by our livedata. observe method.
        observer.mObserver.onChanged((T) mData);
    }
Copy the code

If inactive, return, and activeStateChanged again, passing false, internally judged again. The onChange method is eventually called, which is the observer event callback.

Here we see that the version check is done, but not the same value, so the subscribed observers will still receive the same value when the same value is set.

Data update postValue/setValue

Now let’s look at how postValue and setValue update data.

/ / postValue calls
    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
      // The child thread can execute again
        if(! postTask) {return;
        }
      // Finally call mainHandler. post(runnable) to do a thread switch
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

	// Child thread implementation
  private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run(a) {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
          // Finally call setValuesetValue((T) newValue); }};Copy the code

The posetValue method puts mPostValueRunnable on the main thread, and in the run method main eventually calls the setValue method.

# # setValue callsprotected void setValue(T value) {
      // Check whether the current thread is in the main thread
        assertMainThread("setValue");
      / / version
        mVersion++;
        mData = value;
      // Also distribute values
        dispatchingValue(null);
    }
Copy the code

You can see that setValue is running in the main thread, internally calling the dispatchingValue method. And this is what we know from the above analysis, the dispatchingValue method with a null parameter is going to go through and notify all the observers.

So both the setValue and postValue methods call the dispatchingValue method.

How to use observeForever

If there are observers that will not be removed, there is an answer.

 public void observeForever(@NonNull Observer<? super T> observer) {
        assertMainThread("observeForever");
   			// Wrap class AlwaysActiveObserver
        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);
    }
Copy the code

Within a method called directly the wrapper. ActiveStateChanged (true), was introduced into the true, to ensure the internal finally will go dispatchingValue method, with the different packing type AlwaysActiveObserver again at the same time, AlwaysActiveObserver code

private class AlwaysActiveObserver extends ObserverWrapper {

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

        @Override
        boolean shouldBeActive(a) {
          // It is very simple to make it independent of the life cycle and write the return value to true
            return true; }}Copy the code

Quite simply, it does not depend on the life cycle to determine whether it is active or not, and simply writes the return value to true. ShouldBeActive () when considered as an observer, let the component remain Active.

How do sticky events happen

Having completed the analysis of LiveData source code, now we will analyze the problems encountered in the development:

Why does a subscriber observer called LiveData# Observe receive an old value when LiveData has a value?

When a new observer is registered, the observed sends the old value to the observer. Now let’s return to notice:

private void considerNotify(ObserverWrapper observer) {
    if(! observer.mActive) {return; }...// since the observer is newly created, observer.mlastversion should be the initial value LiveData#START_VERSION -1
    Since LiveData is not the first distribution value, mVersion must be greater than the initial value start_version-1
    // This condition is invalid
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    // Assign the mVersion of LiveData to observer.mlastVersion
    observer.mLastVersion = mVersion;
    // Call onChanged which is the onChanged of the Observer object passed in livedata. observe
    observer.mObserver.onChanged((T) mData);
}
Copy the code

Obser.mlaseversion has not yet been assigned because the observer was created when the new observer subscribed, and is equal to START_VERSION (-1). This is not the first time that mVersion has been distributed, so mVersion must be greater than the initial value of start_version-1. Therefore, observer.mLastVersion >= mVersion caused the sticky event exception.

The specific solution is to look at LiveData data inversion: don’t ask, ask is unanticipated and refer to unpeek-LiveData source code.

To summarize, there are several cases where LiveData will distribute values:

  1. Call setValue and postValue and LifecycleOwner is active
  2. Call LiveData# Observe subscriber observer when LiveData has a value and is active
  3. LiveData has a new value, that is, mLastVersion of ObserverWrapper is less than mVersion of LiveData, LifecycleOwner goes from inactive to active

conclusion

Finally, the relational class diagram of LiveData:

Pictures from — a guide to Understand LiveData(Principles)

In the process of analyzing the source code, tracking most of the associated classes are in it, combined with this picture is not to have a clearer understanding of LiveData.

reference

LiveData Official Documentation – Overview of LiveData

Jetpack AAC complete parsing (ii) Full mastery of LiveData

This article introduces you to LiveData(Principles)

Learn Android again: LiveData data backflow background reason full picture exclusive analysis