1.介绍
MediatorLiveData
是一个LiveData
的子类,它将活跃状态或者非活跃状态传播到源LiveData
上;也就是说它相当于是一个中间商,通过addSource
进行注册的LiveData
,当数据进行更新时通过中间商倒一手再进行处理。
2.具体使用
我们看一下官方介绍的两个场景:
- 有多个
LiveData
,我们想要同时监听这两个数据源,只要他们之中有一个数据源更新则接收到通知
我们看一下具体需要怎么做:
//1.第一个数据源
LiveData liveData1 = ...;
//第二个数据源
LiveData liveData2 = ...;
//2.中间商
MediatorLiveData liveDataMerger = new MediatorLiveData<>();
liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value)//数据源1更新后通知中间商更新);
liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value)//数据源2更新后通知中间商更新);
//3.通过改变数据源1或者2的数据,中间商接收到更新了
liveDataMerger.observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.i("hellokai", "mediatorLiveData, onChanged:" + s);
}
});
- 如果数据源变化频繁,我们想要只检测前10个数据变化,之后取消数据观察,我们可以用中间商这么做:
liveDataMerger.addSource(liveData1, new Observer() {
private int count = 1;
@Override public void onChanged(@Nullable Integer s) {
count++;
//1.当数据源1更新后,通知中间商进行更新
liveDataMerger.setValue(s);
//2.满足条件后,我们进行取消
if (count > 10) {
liveDataMerger.removeSource(liveData1);
}
}
});
可以看到我们没有影响原数据的注册和解注册,使用中间商倒一手可以灵活实现了!
3.源码分析
这个类总共不到200行代码,比较少,我们具体通过常用方法分析一下如何实现的
3.1来看一下addSource
这个方法
public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
//创建了一个新的source对象看3.2
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;
}
//如果这个中间商之前通过数据更新,则在此进行注册,防止在onChanged数据解绑定再注册没有注册的问题
if (hasActiveObservers()) {
e.plug();
}
}
3.2来看一下Source
这个类
//继承自observer
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注册一直是active状态,直到调用removeObserver
mLiveData.observeForever(this);
}
void unplug() {
mLiveData.removeObserver(this);
}
@Override
public void onChanged(@Nullable V v) {
//将当前的mVersion和mLiveData.getVersion()进行绑定
if (mVersion != mLiveData.getVersion()) {
mVersion = mLiveData.getVersion();
mObserver.onChanged(v);
}
}
}
3.3既然是LiveData
的子类,再看一下onActive()
和onInactive()
这两个方法
@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();
}
}
我们可以知道了mSources
是在调用addSource()
方法时绑定的数据源,当此中介者处于活跃状态时,进行注册和数据分发处理,如果是非活跃状态,也进行解注册。
4.Transformations
使用分析
map()
和switchMap()
方法使用到了MediatorLiveData
这个类,使用同RxJava
中的map()
,flatmap()
方法使用是类似的;我们也来分析一下它的具体作用
public static <X, Y> LiveData<Y> map(
@NonNull LiveData<X> source,
@NonNull final Function<X, Y> mapFunction) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(source, new Observer<X>() {
@Override
public void onChanged(@Nullable X x) {
result.setValue(mapFunction.apply(x));
}
});
return result;
}
可以看到,使用了中间商MediatorLiveData
,绑定了源数据,当源数据改变的时候会用此Function
来进行通知
我们再来看一下switchMap()
这个方法:
public static <X, Y> LiveData<Y> switchMap(
@NonNull LiveData<X> source,
@NonNull final Function<X, LiveData<Y>> switchMapFunction) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(source, new Observer<X>() {
LiveData<Y> mSource;
@Override
public void onChanged(@Nullable X x) {
//1.获取到LiveData
LiveData<Y> newLiveData = switchMapFunction.apply(x);
//2.判断LiveData是否是新的,如果不是新的则返回
if (mSource == newLiveData) {
return;
}
//3.如果是新的,则先解注册
if (mSource != null) {
result.removeSource(mSource);
}
mSource = newLiveData;
if (mSource != null) {
//4.再将新的LiveData进行注册
result.addSource(mSource, new Observer<Y>() {
@Override
public void onChanged(@Nullable Y y) {
result.setValue(y);
}
});
}
}
});
return result;
}
那它的具体使用场景是什么呢?我们来看一下如果我们在ViewModel
中直接返回了Repository
的LiveData
那么因为Repository
产生的LiveData
每次返回的都是一个新的LiveData
,这样如果不重新解注册之前的,重新注册新的就会有问题,这个时候我们就可以使用switchMap
来做了,通过源码分析我们看到了,它会解注册之前的再注册新的LiveData
我们以官方文档中的例子再具体分析一下:
class MyViewModel extends ViewModel {
private final PostalCodeRepository repository;
public MyViewModel(PostalCodeRepository repository) {
this.repository = repository;
}
private LiveData<String> getPostalCode(String address) {
// 无论是通过网络retrofit还是走数据库都是返回的新的LiveData,直接返回的话,相当于每次都是重新注册的一个新的LiveData,没有必要
return repository.getPostCode(address);
}
}
可以使用switchMap()
来做一个转换进行处理:
class MyViewModel extends ViewModel {
private final PostalCodeRepository repository;
private final MutableLiveData<String> addressInput = new MutableLiveData();
//1.使用switchMap来保证只注册一个LiveData
public final LiveData<String> postalCode =
Transformations.switchMap(addressInput, (address) -> {
return repository.getPostCode(address);
});
public MyViewModel(PostalCodeRepository repository) {
this.repository = repository
}
//2.外部通过设置此方法来进行更新
private void setInput(String address) {
addressInput.setValue(address);
}
}
以上我们就清楚了它的使用场景了!