/* * 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. *
* This class correctly propagates its active/inactive states down to source {@code LiveData} * objects. *
* 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}. * *
* 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)); **
* 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. *
* 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); * } * } * }); ** * @param
* {@code onChanged} callback will be called only when this {@code MediatorLiveData} is active. *
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 The type of data hold by {@code source} LiveData
*/
@MainThread
public void addSource(@NonNull LiveData source, @NonNull Observer super S> onChanged) {
if (source == null) {
throw new NullPointerException("source cannot be null");
}
Source 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 the type of data hold by {@code source} LiveData
*/
@MainThread
public void removeSource(@NonNull LiveData toRemote) {
Source> source = mSources.remove(toRemote);
if (source != null) {
source.unplug();
}
}
@CallSuper
@Override
protected void onActive() {
for (Map.Entry