Android架构组件(3)LiveData框架

文章目录

    • LiveData介绍
      • LiveData的实现类
    • 源码分析
      • LiveData的实现
      • MediatorLiveData的实现
      • Transformations工具类
      • ComputableLiveData类
    • 小结

LiveData介绍

LiveData是一个用于构建数据流的响应式框架,简单来讲的话,它就相当于一个砍掉了所有操作符的RxJava。
LiveData框架中的数据源为LiveData类,这是一个泛型类,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, ObserverWrapper>类型的属性mObservers管理所有订阅者(这个类在上一节有过介绍,这里就不赘述了),其中ObserverWrapperObserver的封装类,它增加了一个mLastVersion属性和shouldBeActive抽象方法,只有在mLastVersion小于mVersionshouldBeActive返回true时,LiveData才会在更新数据时回调这个Observer
ObserverWrapper有两个子类:LifecycleBoundObserverAlwaysActiveObserver,分别对应了observe(LifecycleOwner owner, Observer observer)observeForever(Observer 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时,表示是有新订阅者注册,需要将当前值发送给新的订阅者。除此之外,mDispatchInvalidatedmDispatchingValue同样是处理嵌套请求的情况,这里也不赘述了。

MediatorLiveData的实现

因为MutableLiveData的实现只是开放了setValuepostValue接口,就不多说了,直接看它的子类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,然后在SourceonChanged方法中调用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();
        }
    }

onActiveonInactiveLiveData中声明,其中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最终还是基于简单的订阅者模式。抓住订阅、发布两条线来走流程,并且注意看它是怎么解决这类框架都会遇到的问题,理解起来才更轻松,这终究还是一个经验积累的过程。

你可能感兴趣的:(Android)