文章目录
LiveData介绍
LiveData是一个用于构建数据流的响应式框架,简单来讲的话,它就相当于一个砍掉了所有操作符的RxJava。
LiveData框架中的数据源为LiveData<T>类,这是一个泛型类,T是它持有的数据的类型。它的API如下
public abstract class LiveData<T> {
public T getValue()
public boolean hasActiveObservers()
public boolean hasObservers()
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)
@MainThread
public void observeForever(@NonNull Observer<? super T> observer)
@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer)
@MainThread
public void removeObservers(@NonNull final LifecycleOwner owner)
}
LiveData主要声明了注册和反注册的接口,注册有两种方式,一是使用observe方法,这个方法需要LifecycleOwner参数,这个方法注册的订阅者,只有在owner的生命状态处于STARTED或者RESUMED状态的时候才会收到数据改变的回调;还有一种注册方式是observeForever方法,这种方式注册的订阅者就是一直生效的,所以可能会造成内存泄漏,需要及时调用removeObserver方法反注册,相对应的,还有removeObservers方法反注册这个LifecycleOwner的所有订阅者。
LiveData的订阅者Observer的接口如下:
public interface Observer<T> {
void onChanged(T t);
}
当LiveData持有的数据改变时,它的所有(活跃的)订阅者的onChanged的方法会被调用,最新的值作为参数传给订阅者。
LiveData的实现类
细心的读者会发现LiveData类提供了读取值的接口,却没有提供写入值的接口,这是因为LiveData将它设置值的方法的访问级别设为了protected:
@MainThread
protected void setValue(T value)
protected void postValue(T value)
LiveData有两个方法可以写入值,其中setValue只能在主线程调用,而postValue则可以在子线程中调用。
写入的两个方法的访问级别在LiveData的子类MutableLiveData开放:
public class MutableLiveData<T> extends LiveData<T> {
...
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
MutableLiveData唯一的改变就是将两个写入方法公开了。
MutableLiveData已经具有了读取、写入值,注册、反注册订阅者的完整功能。而它的子类MediatorLiveData还提供了LiveData之间的订阅功能:
public class MediatorLiveData<T> extends MutableLiveData<T> {
@MainThread
public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged)
@MainThread
public <S> void removeSource(@NonNull LiveData<S> toRemote)
}
MediatorLiveData声明了addSource接口,当source的值改变时,会调用onChanged回调,MediatorLiveData可以在onChanged中根据source的值更新自己的值,这样就构成了LiveData的连续响应。
源码分析
LiveData同样是基于订阅者模式实现的,而它和Lifecycles的区别是,LiveData框架中没有一个独立管理类,管理的功能也由被订阅者LiveData内部实现了,所以接下来,我将基于LiveData和它的子类来分析LiveData框架的实现原理。
LiveData的实现
LiveData虽然是个抽象类,但它实际上已经将基本的功能和框架都实现了。它使用int属性mVersion来记录当前数据的版本号,使用SafeIterableMap<Observer<? super T>, ObserverWrapper>类型的属性mObservers管理所有订阅者(这个类在上一节有过介绍,这里就不赘述了),其中ObserverWrapper是Observer的封装类,它增加了一个mLastVersion属性和shouldBeActive抽象方法,只有在mLastVersion小于mVersion且shouldBeActive返回true时,LiveData才会在更新数据时回调这个Observer。
ObserverWrapper有两个子类:LifecycleBoundObserver和AlwaysActiveObserver,分别对应了observe(LifecycleOwner owner, Observer<? super T> observer)和observeForever(Observer<? super T> observer)两个接口。
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
final LifecycleOwner mOwner;
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
...
}
private class AlwaysActiveObserver extends ObserverWrapper {
@Override
boolean shouldBeActive() {
return true;
}
}
LifecycleBoundObserver会根据传入的LifecycleOwner的生命状态来判断是否Observer是否应该受到回调,并且当它的生命周期到了DESTROYED的时候,还会自动调用反注册方法取消注册。
接下来看LiveData更新数据的实现,先说postValue的实现,它是使用Handler在主线程执行mPostValueRunnable来更新值的,最终调用的还是setValue方法。
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
这里还有一个小细节,因为postValue可能存在多个线程同时调用的情况,所以为了少执行mPostValueRunnable,Google将Handler的调用移到了同步锁之外,通过mPendingData 是否等于 NOT_SET来判断是否有值已经赋给了mPendingData,但还没有同步到newValue(即有一个mPostValueRunnable在队列中还未执行),进而决定是不是还需要调用mPostValueRunnable。这种做法造成的后果是当postValue同时调用多次时,mPostValueRunnable只调用一次,mPendingData的值会等于最后一个获取到锁的线程设置的值,即其他线程设置的值都会丢失。这个是使用时要注意的。
而在setValue中,在mVersion+1之后,LiveData紧接着就是调用dispatchingValue方法来通知所有订阅者:
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
dispatchingValue方法有一个参数,当initiator为null时,表示是LiveData更新了值在通知所有订阅者,不为null时,表示是有新订阅者注册,需要将当前值发送给新的订阅者。除此之外,mDispatchInvalidated和mDispatchingValue同样是处理嵌套请求的情况,这里也不赘述了。
MediatorLiveData的实现
因为MutableLiveData的实现只是开放了setValue和postValue接口,就不多说了,直接看它的子类MediatorLiveData的实现,前面已经提到,MediatorLiveData增加了addSource接口,来实现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 (hasActiveObservers())
e.plug();
}
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);
}
}
}
在addSource方法中,MediatorLiveData会将数据源source封装成实现了Observer接口的Source 类对象,调用plug方法订阅source,然后在Source 的onChanged方法中调用addSource方法中传入的onChanged回调。接下来source的值的变化就都会通知到onChanged,直到调用removeSource方法,调用unplug方法解除和source的绑定为止。
除了上述绑定和解除绑定的过程,MediatorLiveData中还有两个方法会影响到它和数据源的订阅关系:
@Override
protected void onActive() {
for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
source.getValue().plug();
}
}
@Override
protected void onInactive() {
for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
source.getValue().unplug();
}
}
onActive和onInactive在LiveData中声明,其中onActive会在LiveData获得第一个订阅者(包括之前有订阅者但是又已经全部反注册的情况)之后调用,onInactive会在LiveData失去了所有订阅者的时候调用。所以当MediatorLiveData失去了所有订阅者之后,它会解除和所有数据源的订阅关系,直到又有新的订阅者注册再重新注册所有数据源。
Transformations工具类
我在最开头的时候说过,LiveData框架相当于一个砍掉了所有操作符的RxJava,这是LiveData的设计思想决定的,虽然这种“小而美”的思路很好,但是有时候我们在做LiveData数据流处理的时候,还是会需要那些操作符,因此Google提供了Transformations工具类来提供一些操作符:
public class Transformations {
@MainThread
public static <X> LiveData<X> distinctUntilChanged(LiveData<X> source)
@MainThread
public static <X, Y> LiveData<Y> map(LiveData<X> source,final Function<X, Y> mapFunction)
@MainThread
public static <X, Y> LiveData<Y> switchMap( LiveData<X> source,final Function<X, LiveData<Y>> switchMapFunction)
}
它们的实现我就不多说了,简单介绍一下它们的功能,相信熟悉RxJava的朋友不难看出它们的原型:
- distinctUntilChanged:LiveData只要更新值就会触发回调,这个方法的功能就是过滤
source,只有当前值跟之前的值不一样的时候才会触发回调。 - map:将source的输入根据mapFunction转换成不同类型的输出。
- switchMap:将source的输入根据switchMapFunction转换成不同类型的LiveData。
ComputableLiveData类
上述类已经构建了一个完整的响应式框架,但是我在看源码的时候,发现居然还有一个ComputableLiveData类!这个类虽然名字里面带了“LiveData”,但它并没有继承LiveData类,而是有一个提供LiveData的接口:
public abstract class ComputableLiveData<T> {
public ComputableLiveData(@NonNull Executor executor)
public LiveData<T> getLiveData()
public void invalidate()
protected abstract T compute();
}
从实现上来说,ComputableLiveData可以被视作一个FutureTask,区别在于,它没有get接口,取而代之的是getLiveData接口,它会执行抽象方法compute,然后通过LiveData返回结果。ComputableLiveData还提供了invalidate方法来使原来的值无效化并重新调用compute计算值。
ComputableLiveData类看起来并不是LiveData框架的组件,更像是Transformations类这样的工具类。
小结
LiveData可以说是学习成本最低的响应式框架了,虽然这么说,但它还是我这系列文章里面实现最复杂的。在学习它的源码的时候,给我感触最深的是它最难的不是代码实现,而是理解它的设计思路,这已经是在去掉了操作符的情况下,由此可见RxJava是多么的复杂!但是剥去层层的外衣可以看到,LiveData最终还是基于简单的订阅者模式。抓住订阅、发布两条线来走流程,并且注意看它是怎么解决这类框架都会遇到的问题,理解起来才更轻松,这终究还是一个经验积累的过程。
LiveData是一个用于构建数据流的响应式框架,本文详细介绍了LiveData的基本概念、实现原理及其子类的特性,包括LiveData的数据源、订阅者机制、源码分析以及Transformations工具类的使用。
7452

被折叠的 条评论
为什么被折叠?



