public class

MediatorLiveData<T>

extends MutableLiveData<java.lang.Object>

 java.lang.Object

androidx.lifecycle.LiveData<java.lang.Object>

androidx.lifecycle.MutableLiveData<java.lang.Object>

↳androidx.lifecycle.MediatorLiveData<T>

Gradle dependencies

compile group: 'androidx.lifecycle', name: 'lifecycle-livedata', version: '2.5.0-rc01'

  • groupId: androidx.lifecycle
  • artifactId: lifecycle-livedata
  • version: 2.5.0-rc01

Artifact androidx.lifecycle:lifecycle-livedata:2.5.0-rc01 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.lifecycle:lifecycle-livedata android.arch.lifecycle:livedata

Androidx class mapping:

androidx.lifecycle.MediatorLiveData android.arch.lifecycle.MediatorLiveData

Overview

LiveData subclass which may observe other LiveData objects and react on OnChanged events from them.

This class correctly propagates its active/inactive states down to source LiveData objects.

Consider the following scenario: 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 liveDataMerger.

 LiveData liveData1 = ...;
 LiveData liveData2 = ...;

 MediatorLiveData liveDataMerger = new MediatorLiveData<>();
 liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));
 liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));
 

Let's consider that we only want 10 values emitted by liveData1, to be merged in the liveDataMerger. Then, after 10 values, we can stop listening to liveData1 and remove it as a source.

 liveDataMerger.addSource(liveData1, new Observer() {
      private int count = 1;

       @Override public void onChanged(@Nullable Integer s) {
          count++;
          liveDataMerger.setValue(s);
          if (count > 10) {
              liveDataMerger.removeSource(liveData1);
          }
      }
 });
 

Summary

Constructors
publicMediatorLiveData()

Methods
public voidaddSource(LiveData<java.lang.Object> source, Observer<java.lang.Object> onChanged)

Starts to listen the given source LiveData, onChanged observer will be called when source value was changed.

protected voidonActive()

Called when the number of active observers change from 0 to 1.

protected voidonInactive()

Called when the number of active observers change from 1 to 0.

public voidremoveSource(LiveData<java.lang.Object> toRemote)

Stops to listen the given LiveData.

from MutableLiveData<T>postValue, setValue
from LiveData<T>getValue, hasActiveObservers, hasObservers, observe, observeForever, removeObserver, removeObservers
from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public MediatorLiveData()

Methods

public void addSource(LiveData<java.lang.Object> source, Observer<java.lang.Object> onChanged)

Starts to listen the given source LiveData, onChanged observer will be called when source value was changed.

onChanged callback will be called only when this MediatorLiveData is active.

If the given LiveData is already added as a source but with a different Observer, java.lang.IllegalArgumentException will be thrown.

Parameters:

source: the LiveData to listen to
onChanged: The observer that will receive the events

public void removeSource(LiveData<java.lang.Object> toRemote)

Stops to listen the given LiveData.

Parameters:

toRemote: LiveData to stop to listen

protected void onActive()

Called when the number of active observers change from 0 to 1.

This callback can be used to know that this LiveData is being used thus should be kept up to date.

protected void onInactive()

Called when the number of active observers change from 1 to 0.

This does not mean that there are no observers left, there may still be observers but their lifecycle states aren't Lifecycle.State.STARTED or Lifecycle.State.RESUMED (like an Activity in the back stack).

You can check if there are observers via LiveData.hasObservers().

Source

/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.lifecycle;

import androidx.annotation.CallSuper;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.arch.core.internal.SafeIterableMap;

import java.util.Map;

/**
 * {@link LiveData} subclass which may observe other {@code LiveData} objects and react on
 * {@code OnChanged} events from them.
 * <p>
 * This class correctly propagates its active/inactive states down to source {@code LiveData}
 * objects.
 * <p>
 * Consider the following scenario: we have 2 instances of {@code LiveData}, let's name them
 * {@code liveData1} and {@code liveData2}, and we want to merge their emissions in one object:
 * {@code liveDataMerger}. Then, {@code liveData1} and {@code liveData2} will become sources for
 * the {@code MediatorLiveData liveDataMerger} and every time {@code onChanged} callback
 * is called for either of them, we set a new value in {@code liveDataMerger}.
 *
 * <pre>
 * LiveData<Integer> liveData1 = ...;
 * LiveData<Integer> liveData2 = ...;
 *
 * MediatorLiveData<Integer> liveDataMerger = new MediatorLiveData<>();
 * liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));
 * liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));
 * </pre>
 * <p>
 * Let's consider that we only want 10 values emitted by {@code liveData1}, to be
 * merged in the {@code liveDataMerger}. Then, after 10 values, we can stop listening to {@code
 * liveData1} and remove it as a source.
 * <pre>
 * liveDataMerger.addSource(liveData1, new Observer<Integer>() {
 *      private int count = 1;
 *
 *      {@literal @}Override public void onChanged(@Nullable Integer s) {
 *          count++;
 *          liveDataMerger.setValue(s);
 *          if (count > 10) {
 *              liveDataMerger.removeSource(liveData1);
 *          }
 *      }
 * });
 * </pre>
 *
 * @param <T> The type of data hold by this instance
 */
@SuppressWarnings("WeakerAccess")
public class MediatorLiveData<T> extends MutableLiveData<T> {
    private SafeIterableMap<LiveData<?>, Source<?>> mSources = new SafeIterableMap<>();

    /**
     * Starts to listen the given {@code source} LiveData, {@code onChanged} observer will be called
     * when {@code source} value was changed.
     * <p>
     * {@code onChanged} callback will be called only when this {@code MediatorLiveData} is active.
     * <p> If the given LiveData is already added as a source but with a different Observer,
     * {@link IllegalArgumentException} will be thrown.
     *
     * @param source    the {@code LiveData} to listen to
     * @param onChanged The observer that will receive the events
     * @param <S>       The type of data hold by {@code source} LiveData
     */
    @MainThread
    public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
        if (source == null) {
            throw new NullPointerException("source cannot be null");
        }
        Source<S> e = new Source<>(source, onChanged);
        Source<?> existing = mSources.putIfAbsent(source, e);
        if (existing != null && existing.mObserver != onChanged) {
            throw new IllegalArgumentException(
                    "This source was already added with the different observer");
        }
        if (existing != null) {
            return;
        }
        if (hasActiveObservers()) {
            e.plug();
        }
    }

    /**
     * Stops to listen the given {@code LiveData}.
     *
     * @param toRemote {@code LiveData} to stop to listen
     * @param <S>      the type of data hold by {@code source} LiveData
     */
    @MainThread
    public <S> void removeSource(@NonNull LiveData<S> toRemote) {
        Source<?> source = mSources.remove(toRemote);
        if (source != null) {
            source.unplug();
        }
    }

    @CallSuper
    @Override
    protected void onActive() {
        for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
            source.getValue().plug();
        }
    }

    @CallSuper
    @Override
    protected void onInactive() {
        for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
            source.getValue().unplug();
        }
    }

    private static class Source<V> implements Observer<V> {
        final LiveData<V> mLiveData;
        final Observer<? super V> mObserver;
        int mVersion = START_VERSION;

        Source(LiveData<V> liveData, final Observer<? super V> observer) {
            mLiveData = liveData;
            mObserver = observer;
        }

        void plug() {
            mLiveData.observeForever(this);
        }

        void unplug() {
            mLiveData.removeObserver(this);
        }

        @Override
        public void onChanged(@Nullable V v) {
            if (mVersion != mLiveData.getVersion()) {
                mVersion = mLiveData.getVersion();
                mObserver.onChanged(v);
            }
        }
    }
}