“This is the second day of my participation in the First Challenge 2022.

preface

The principle of LiveData has been introduced in the previous article, which is very important. It involves multiple features of LiveData. You can read the previous article first:

LiveData source code analysis 2 — Principle Analysis – Digging gold (juejin. Cn)

MediatorLiveData is an important class that uses LiveData.

MediatorLiveData overview of

Or the old way, look at the source first look at the notes. Here MediatorLiveData is directly translated as the intermediate LiveData, which is the LiveData derived from other LiveData.

Valid comments are as follows:

LiveData subclass which may observe other LiveData objects and react on OnChanged events from them.
Copy the code
  • Is a subclass of LiveData that can observe other LiveData objects and react to their onChanged events.

Here is a simple example, directly look at the comments also give examples:

we have 2 instances of LiveData, 
let's name them liveData1 and liveData2, and we want to merge their emissions in one object: liveDataMerger. Then, liveData1 and liveData2 will become sources for the MediatorLiveData liveDataMerger and every time onChanged callback is  called for either of them, we set a new value in liveDataMergerCopy the code
  • Suppose you have a LiveData named liveData1 and liveData2, and then put their emission products into an object called liveDataMerger.

  • Then liveData1 and liveData2 are the sources of the intermediate LiveData, and each time the onChanged method of the source LiveData is called, a new value is generated for the liveDataMerger.

As you can see from this description, MediatorLiveData can have multiple LiveData sources, and when these source LiveData changes, new values are generated in MediatorLiveData.

Simple use of MediatorLiveData

Since MediatorLiveData is a combination of multiple LiveData, you must add the source LiveData to the MediatorLiveData and how the MediatorLiveDta will change when the value in the source LiveData changes. There must be a rule for this, so its simple use is as follows:

   / / 2 LiveDataLiveData liveData1 = ... ; LiveData liveData2 = ... ;// Create a MediatorLiveData instance
   MediatorLiveData  liveDataMerger = new MediatorLiveData<>();
   // Add the source LiveData using the addSource method, while processing the value
   liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));
   liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));
Copy the code

For example, in the code above, if either liveData1 or liveData2 changes, it will change in the liveDataMerger.

The principle of analytic

MediatorLiveData is a subclass of LiveData and can be set to a value, so it should inherit from MutableLiveData. Let’s look at the source code of MediatorLiveData:

/ / the source code
public class MediatorLiveData<T> extends MutableLiveData<T> {
    // See analysis 1 for the Source used to store LiveDataprivate SafeIterableMap<LiveData<? >, Source<? >> mSources =new SafeIterableMap<>();

    // Add source LiveData and observer
    @MainThread
    public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
        //Source see analysis 1
        Source<S> e = new Source<>(source, onChanged);
        // Add source to the listSource<? > existing = mSources.putIfAbsent(source, e);// If the liveData has been added to the list, but the onChange is different, it is considered an error
        if(existing ! =null&& existing.mObserver ! = onChanged) {throw new IllegalArgumentException(
                    "This source was already added with the different observer");
        }
        if(existing ! =null) {
            return;
        }
        // Check whether MediatorLiveData has active observers
        if (hasActiveObservers()) {
            // Start ee.plug(); }}// Remove the observer
    @MainThread
    public <S> void removeSource(@NonNull LiveData<S> toRemote){ Source<? > source = mSources.remove(toRemote);if(source ! =null) { source.unplug(); }}// When the current LiveData has active observers
    @CallSuper
    @Override
    protected void onActive() {
        for (Map.Entry<LiveData<? >, Source<? >> source : mSources) { source.getValue().plug(); }}// When the current LiveData has no active observer
    @CallSuper
    @Override
    protected void onInactive() {
        for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
            source.getValue().unplug();
        }
    }
}
Copy the code

Analysis 1: When livadata and Observer objects are added, it encapsulates them as a Srouce object, so let’s first look at what the Srouce object does:

// A special observer
private static class Source<V> implements Observer<V> {
    / / source LiveData
    final LiveData<V> mLiveData;
    // Observer passed by the addSource method
    final Observer<? super V> mObserver;
    int mVersion = START_VERSION;

    Source(LiveData<V> liveData, final Observer<? super V> observer) {
        mLiveData = liveData;
        mObserver = observer;
    }
    
    // Plug in, which means to make this liveData valid
    void plug() {
        // Note that forever is added here, regardless of the life cycle
        mLiveData.observeForever(this);
    }
    
    // Unplug this liveData
    void unplug() {
        mLiveData.removeObserver(this);
    }

    // Only when the data version changes is called back
    @Override
    public void onChanged(@Nullable V v) {
        if(mVersion ! = mLiveData.getVersion()) { mVersion = mLiveData.getVersion(); mObserver.onChanged(v); }}}Copy the code

The above code is still easy to understand, so let me summarize a few points:

  • Lifecycle of the added source Livedata will be listened for via observeForever without the need for a corresponding Lifecycle, just plug in and listen for changes.

  • Listen for changes to each source LiveData only if MediatorLiveData has an active observer, the onActive function call, to reduce system resources.

  • As long as MediatorLiveData is listened on and there is a Lifecycle, whether or not the source LiveData is active will be mapped to MediatorLiveData regardless of what the source LiveData is. As long as MediatorLiveData’s Lifecycle is active, it listens.

  • It is normal logic to report an error when adding different observers (that is, transformation rules) to the same source LiveData.

conclusion

MediatorLiveData is a class that can merge multiple sources of LiveData. It flexibly uses onActive and onInactive methods to reduce resource usage. There are many more uses of MediatorLiveData in this article