Jetpack篇——LiveData扩展之MediatorLiveData源码分析

一、分析内容

上篇文章 中有了解过 MediatorLiveData 的使用过程,虽然使用的过程很简单,但是却出现了一个又一个的疑问……所以本篇文章就和大家一起来刨根问底,解疑答惑:

  1. 为什么 MediatorLiveData 需要激活才能够接管 LiveData 的响应事件?
  2. 怎么激活 MediatorLiveData
  3. 为什么 MediatorLiveDataobserve() 或者 observeForever 的匿名类没有发生回调?

二、为什么 MediatorLiveData 需要激活才能够接管 LiveData 的响应事件?

先请出我们的主角方法 addSource()

	//为了更好的分析描述,不使用 Lamboda
	mediatorLiveData.addSource(originData, object : Observer<String>{
    
    	
        override fun onChanged(it: String?) {
    
    
            Log.e("==>liveData","addSourceObserver:$it")
        }
    })

很明显,我们只需要了解 onChanged() 在什么时候会被调用,所以继续查看 addSource() 的源码:

private SafeIterableMap<LiveData<?>, Source<?>> mSources = new SafeIterableMap<>();

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);
    //无关代码
    ... ...
}

本来我们是想找找看 onChanged.onChanged(T) 会不会在这里调用,但是我们却发现 源LiveData对象 source 和回调接口 onChanged 被包装到一个 Source 的类中,我们再看看这个类,他是 MediatorLiveData 私有化的静态内部类:

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);	//2
    }
    void unplug() {
    
    
        mLiveData.removeObserver(this);
    }
    @Override
    public void onChanged(@Nullable V v) {
    
    
        if (mVersion != mLiveData.getVersion()) {
    
    
            mVersion = mLiveData.getVersion();
            mObserver.onChanged(v);	//1
        }
    }
}

我们先看到构造方法,传入的两个参数分别都赋值给了类的内部属性:mLiveDatamObserver,所以我们找找看,有没有 mObserver.onChanged(T) 这个方法,就在 标记 1 的位置。

但是我们发现这里被一个 Observer<T> 接口的方法 onChanged() 包裹住了,那么这个方法怎么调用呢?

我们直接把目光放到 标记 2 的位置。这个 mLiveData 是什么还记得吗?就是 addSource() 时,传来的被接管的 LiveData 对象。当这行代码被执行,那么 mLiveData 值的变化就会影响到 Source 这个类,那么就会调用 onChanged() 方法,从而才有机会继续调用mObserver.onChanged(T)

小结:所以我们需要调用到 void plug() 这个方法,才能够“激活” MediatorLiveData,使得匿名类的 onChanged(T) 方法能够被调用。

那么问题来了:void plug() 这个方法何时会被调用?

扫描二维码关注公众号,回复: 11978045 查看本文章

三、怎么激活 MediatorLiveData?

我们跟踪 plug() 可以发现有两条路线:

1. 路线一 ——observeForever()

public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
    
    
    ... ...
    if (hasActiveObservers()) {
    
    
        e.plug();
    }
}

public boolean hasActiveObservers() {
    
    
    return mActiveCount > 0;
}

void activeStateChanged(boolean newActive) {
    
    
    ... ...
    LiveData.this.mActiveCount += mActive ? 1 : -1;
  	... ...
}

我们一层一层的往下找,发现如果调用 activeStateChanged(true) 的话,就可以达到效果,这个地方又有两个地方被调用到:

//第一个地方
public void observeForever(@NonNull Observer<? super T> observer) {
    
    
    ... ...
    wrapper.activeStateChanged(true);
}
//第二个地方(此处先不管)
public void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {
    
    
    if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
    
    
        removeObserver(mObserver);
        return;
    }
    activeStateChanged(shouldBeActive());
}

所以我们可以通过第一个地方来实现激活 MediatorLiveData 的效果,那就是调用 addSuorce() 之前 调用 observeForever() 即可,但是如果我们把 observeForever() 放在 addSuorce() 之后,一样能够激活…… 这又是为什么呢?

如果我们把 observeForever() 放在 addSuorce() 之后,那么当执行到 addSource() 的时候:

public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
    
    
    ... ...
    if (hasActiveObservers()) {
    
    
        e.plug();
    }
}

hasActiveObservers() 一定会返回 false,所以不是在这个地方激活的……所以我们继续执行 observeForever() ,这个时候还是会调用到 wrapper.activeStateChanged(true);

int mActiveCount = 0;

void activeStateChanged(boolean newActive) {
    
    
    ... ...
    mActive = newActive;
    boolean wasInactive = LiveData.this.mActiveCount == 0;	//1
    LiveData.this.mActiveCount += mActive ? 1 : -1;	//2
    if (wasInactive && mActive) {
    
    
        onActive();	//3
    }
    ... ...
}

此时 标记 2 处的 mActiveCount 加个一已经没有任何意义了,因为 hasActiveObservers() 这个判断早就执行并且返回 false 了。

但是我们继续看下去,可以发现能够执行 标记 3 的代码,我们跟踪这个方法:

	@Override
	protected void onActive() {
    
    
        for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
    
    
            source.getValue().plug();
        }
    }

是不是就看到了很熟悉的方法?所以这也是为什么 observeForever() 能够在 addSource() 之后调用,也能够使得 MediatorLiveData 激活了。

2. 路线二——生命周期

我们知道 observeForever()observe() 的区别就是后者多了一个生命周期的管理,所以当我们调用 mediatorLiveData.observe() 之后,就会通过监听生命周期的变化来进行一些操作:

@Override
public void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {
    
    
    if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
    
    
        removeObserver(mObserver);
        return;
    }
    activeStateChanged(shouldBeActive());
}

是不是又看到了熟悉的方法?不用继续分析,我们通过上一个路线的分析就能够得出 observe() 方法为什么能够激活 MediatorLiveData 了。

四、为什么 MediatorLiveData 的 observe() 或者 observeForever 的匿名类没有发生回调?

MediatorLiveData 对象能够接管一个 LiveData 的变化,且回调发生在 addSource() 方法里面,但是我们得通过 observe() 或者 observeForever () 方法才能够激活 MediatorLiveData,而这两个方法也有一个回调事件,可是这个回调事件并没有跟随 LiveData 得变化而调用……

解释也很简单:

MediatorLiveData 是继承自 MutableLiveData 的,所以按照基本法,我们需要调用 mediatorLiveData.setValue()/postValue() 才能够收到 observe()/observeForever () 的回调事件。
pic

五、总结

了解 MediatorLiveData 的源码还是比较重要的,因为有很多骚操作都是要借助这个类来进行的……如果我们了解了该类的源码,那么理解那些骚操作的原理就会非常简单了。

猜你喜欢

转载自blog.csdn.net/catzifeng/article/details/107775686