-
引出MediatorLiveData
有时候我们需要这么一个场景,有多个LiveData,当其中任何一个LiveData产生变化时我们都要响应某些操作,当然你可以选择每个LiveData都调用observe方法设置相关回调,不过缺点是你会有冗余代码,因为你设置的回调都是一样的逻辑,当有更多的数据源的时候,你需要维护更多的地方同步回调操作。
所以MediatorLiveData出现了,MediatorLiveData本身也是一个LiveData,通过它我们只需要调用addSource方法添加多个LiveData,然后我们只需要监听MediatorLiveData这一个LiveData即可,其中任何一个数据源发生变化都会回调到MediatorLiveData这一个LiveData的监听回调中。
比如下面的代码:
val mediatorLiveData = MediatorLiveData<Any>() mediatorLiveData.addSource(liveData01, { mediatorLiveData.value = it }) mediatorLiveData.addSource(liveData02, { mediatorLiveData.value = it }) mediatorLiveData.observe(this){ //liveData01或者liveData02其中之一变化都会走到这里 }
可以看到,在调用addSource方法的时候传入一个Observer回调,你可以在这个回调里做一些别的事情,这个是和第一个LiveData参数是绑定在一起的:
@MainThread public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) { 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(); } }
e.plug()会把livedata和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.observeForever(this); } void unplug() { mLiveData.removeObserver(this); } @Override public void onChanged(@Nullable V v) { if (mVersion != mLiveData.getVersion()) { mVersion = mLiveData.getVersion(); mObserver.onChanged(v); } } }
所以流程就是拿liveData01来说,当liveData01.setValue或者liveData01.postValue方法被调用时,因为liveData01和Source是绑定的,根据LiveData原理,Source的onChanged会被调用,mObserver又是构造时传入的addSource方法的onChange参数,所以就会调用mediatorLiveData.value = it,从而mediatorLiveData的observe回调被触发,达到统一回调的作用。
-
引出Transformations
从上面的过程中我们可以发现一些可以封装简化代码的地方,比如构造过程,MediatorLiveData的出现自然是为了统一处理多个数据源,如果恰好你的使用场景又是统一回调处理的话,那么Transformations就可以派上用场了。
Transformations和MediatorLiveData都是androidx.lifecycle包下的类,Transformations其实就是封装了MediatorLiveData构造的一个工具类,它只有两个静态方法,map和switchMap。
@MainThread 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; }
map方法就是我们上面构造MediatorLiveData的代码,不同的是你可以多设置一个Function,在子数据源回调时对它的结果做进一步的处理后再发送给MediatorLiveData。如果添加多个数据源的话,同样要在map方法之后调用addSource方法进行添加。
还有一种场景是,在某个LiveData回调之后重新设置一个新的LiveData,即只监听一次旧的LiveData,然后就替换成和上面map方法一样的逻辑了。
@MainThread 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) { LiveData<Y> newLiveData = switchMapFunction.apply(x); if (mSource == newLiveData) { return; } if (mSource != null) { result.removeSource(mSource); } mSource = newLiveData; if (mSource != null) { result.addSource(mSource, new Observer<Y>() { @Override public void onChanged(@Nullable Y y) { result.setValue(y); } }); } } }); return result; }
可以看到,上面的source只会使用一次,到了这里的onChanged回调后就移除了,然后添加一个由switchMapFunction.apply方法产生的新的LiveData,使用和map方法中一样的Observer,只不过这里的新的LiveData的回调值没有回调接口可处理,即y的值是原封不动地传给MediatorLiveData的回调的。
网友评论