LiveData源码分析3 -- MediatorLiveData的使用与原理解析

2,419 阅读4分钟

「这是我参与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方法来减少资源使用,这个类再后续还有很多用法,我们后面文章继续