「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」
前言
上篇文章已经介绍了LiveData的原理,非常重要,里面涉及了多个LiveData的特性,可以先阅读前一篇文章:
LiveData源码分析2 -- 原理分析 - 掘金 (juejin.cn)
本片文章主要介绍一下LiveData的一个重要使用类:MediatorLiveData。
MediatorLiveData的概述
还是老办法,看源码先看注释。这里的MediatorLiveData直接翻译就是中间物LiveData,它是由其他LiveData而来的LiveData。
有效注释如下:
LiveData subclass which may observe other LiveData objects and react on OnChanged events from them.
- 是LiveData的子类,它可以观察其他LiveData对象,并对他们的onChanged事件做出反应。
这里说的还是比较简单的,直接看个例子,在注释中也给出了例子:
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和liveData2,然后把他们的发射产物放入到一个对象中,这个对象叫做liveDataMerger。
-
然后liveData1和liveData2就是这个中间LiveData的源了,然后每当源LiveData的onChanged方法被调用时,就会产生一个新值给到这个liveDataMerger。
从这里描述可以看出,MediatorLiveData可以具有多个LiveData源,当这些源LiveData发生变化时,就会在MediatorLiveData产生新的值。
MediatorLiveData的简单使用
既然MediatorLiveData是多个LiveData的合并起来的结果,那肯定就要往这个MediatorLiveData中添加源LiveData以及当源LiveData里的值变化时,这个MediatorLiveDta将如何变化,这肯定有个规则,所以它的简单使用如下:
//2个LiveData
LiveData liveData1 = ...;
LiveData liveData2 = ...;
//创建一个MediatorLiveData实例
MediatorLiveData liveDataMerger = new MediatorLiveData<>();
//通过addSource的方法添加源LiveData,同时对value进行处理
liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));
liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));
比如上面的代码中,只要liveData1和liveData2中有一个数据发生变化,将在liveDataMerger中会变化。
原理解析
从上面使用会发现MediatorLiveData还是蛮简单的,首先它是LiveData子类,而且可以设置值,所以它应该继承至MutableLiveData,我们来看一下它的大概源码:
//源码
public class MediatorLiveData<T> extends MutableLiveData<T> {
//用来存放LiveData以及对应的Source 见分析1
private SafeIterableMap<LiveData<?>, Source<?>> mSources = new SafeIterableMap<>();
//主线程,添加源LiveData,以及observer观察者
@MainThread
public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
//Source见分析1
Source<S> e = new Source<>(source, onChanged);
//老生常谈了,往链表中添加source
Source<?> existing = mSources.putIfAbsent(source, e);
//当链表中已经添加过该liveData了,但是onChange不同,则认为是出错
if (existing != null && existing.mObserver != onChanged) {
throw new IllegalArgumentException(
"This source was already added with the different observer");
}
if (existing != null) {
return;
}
//判断MediatorLiveData是否有活跃的观察者
if (hasActiveObservers()) {
//对e进行启动
e.plug();
}
}
//移除观察者
@MainThread
public <S> void removeSource(@NonNull LiveData<S> toRemote) {
Source<?> source = mSources.remove(toRemote);
if (source != null) {
source.unplug();
}
}
//当当前LiveData有活跃观察者时
@CallSuper
@Override
protected void onActive() {
for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
source.getValue().plug();
}
}
//当当前LiveData没有活跃观察者时
@CallSuper
@Override
protected void onInactive() {
for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
source.getValue().unplug();
}
}
}
分析1:当添加进来livadata和observer对象时,它会把它封装成一个Srouce对象,所以先看一下这个Srouce对象干了什么:
//一个特殊的观察者
private static class Source<V> implements Observer<V> {
//源LiveData
final LiveData<V> mLiveData;
//addSource方法传递的observer
final Observer<? super V> mObserver;
int mVersion = START_VERSION;
Source(LiveData<V> liveData, final Observer<? super V> observer) {
mLiveData = liveData;
mObserver = observer;
}
//插上,也就是让这个liveData有效的意思
void plug() {
//注意这里是添加的forever,和生命周期无关
mLiveData.observeForever(this);
}
//拔掉,也就是让这个liveData无效的意思
void unplug() {
mLiveData.removeObserver(this);
}
//数据版本发生变化时,才进行回调
@Override
public void onChanged(@Nullable V v) {
if (mVersion != mLiveData.getVersion()) {
mVersion = mLiveData.getVersion();
mObserver.onChanged(v);
}
}
}
上面代码还是容易理解的,这里我来给总结几点:
-
被添加进来的源livedata,对源livedata的数据变化监听是通过observeForever来实现的,不需要对应的Lifecycle,只要插上(plug函数调用),就进行监听变化。
-
只有当MediatorLiveData有活跃的观察者即onActive函数调用时,才去监听每个源LiveData的变化,这样可以减少系统资源。
-
只要MediatorLiveData被监听后,有对应的Lifecycle,其源LiveData是否活跃其实就映射到了MediatorLiveData上,不管其源LiveData如何,只要MediatorLiveData对应的Lifecycle处于活跃,便进行监听。
-
当对同一个源LiveData添加不同的observer(即转换规则)时,会报错,这也是正常逻辑。
总结
MediatorLiveData作为可以合并多个源LiveData的类,其中灵活的使用了onActive和onInactive方法来减少资源使用,这个类再后续还有很多用法,我们后面文章继续