阅读 150

LiveData源码分析2 -- 原理分析

前言

本章直接通过上面一章所介绍的LiveData特性,来看一下是如何实现这些特性的。

正文

其实LiveData的核心实现就2个方向,一个是更改其持有的值如何通知到观察者,一个是添加观察者,我们也就从这2方面入手分析。

分发、通知数据变化

先看一下构造函数:

public LiveData(T value) {     //这里使用mData来保存数据     mData = value;     //每操作一次这个数据的version加一     mVersion = START_VERSION + 1; } 复制代码

//LiveData保存的字段 //使用Object来保存数据,根据Kotlin的泛型是伪泛型,且被擦除,所以这里用Object来保存T类型数据 //这里使用volatile来修饰mData,所以要求线程之间是可见的,至于多线程同步,后面细说 private volatile Object mData; 复制代码

//数据版本 private int mVersion; 复制代码

这里构造函数就能看出,要保证多线程同步,接着看:

//主线程修改值 @MainThread protected void setValue(T value) {     assertMainThread("setValue");     mVersion++;     mData = value;     //mData值改变,进行通知分发给观察者     dispatchingValue(null); } 复制代码

//分发值 //ObserverWrapper后面再说 void dispatchingValue(@Nullable ObserverWrapper initiator) {     //当正在分发值时,分发使能无效为true     if (mDispatchingValue) {         mDispatchInvalidated = true;         return;     }     //开始分发值     mDispatchingValue = true;     do {         //一旦开始分发,分发使能无效为false         mDispatchInvalidated = false;         //分发给单个观察者         if (initiator != null) {             considerNotify(initiator);             initiator = null;         } else {             //分发给多个观察者             //特殊集和 见分析1             for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =                     mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {                 //关键代码                 considerNotify(iterator.next().getValue());                 //发现分发使能无效立马停止 见分析2                 if (mDispatchInvalidated) {                     break;                 }             }         }     } while (mDispatchInvalidated);     //分发结束     mDispatchingValue = false; } 复制代码

分析1:这个集和在前面Lifecycle源码有介绍过,它是一个链表形成的map,可以查看文章:juejin.cn/post/705294…

分析2:其实这段代码很有参考意义,这里只能在主线程中执行,由于遍历链表是个耗时操作,所以会出现前面一个值还没有分发完,后面一个值就接着来了,这时使用了2个标志位mDispatchingValue和mDispatchInvalidated来控制,当正在遍历时,发现有新的值需要去分发,这时及时打断遍历,再从头遍历,使用新的值来分发。

这里使用不常用的do while循环来完成这个逻辑,同时也展示了一个LiveData特性:当有多个观察者时,且值变化太快,只能通知最新的值

继续看一下分发代码:

//根据observer来判断是否要通知 private void considerNotify(ObserverWrapper observer) {     //假如observer是非活跃的,就不进行通知     //具体逻辑见分析3     if (!observer.mActive) {         return;     }     //当observer应该是Active为false,则不进行通知     //具体原因见分析4     if (!observer.shouldBeActive()) {         observer.activeStateChanged(false);         return;     }     //当observer值的版本已经比现在要分发的值更新,则不用通知     if (observer.mLastVersion >= mVersion) {         return;     }     //更新值版本     observer.mLastVersion = mVersion;     //进行通知     observer.mObserver.onChanged((T) mData); } 复制代码

这里也就是LiveData的又一个特性:当观察者对应的Lifecycle处于不活跃时,将不会通知

分析3:那就需要看一下这里是如何判断是否活跃的,这里也就是ObserverWrapper类的实现:

//抽象的父类 private abstract class ObserverWrapper {     //观察者     final Observer<? super T> mObserver;     //是否活跃     boolean mActive;     //数据版本     int mLastVersion = START_VERSION;     ObserverWrapper(Observer<? super T> observer) {         mObserver = observer;     }          //子类实现     abstract boolean shouldBeActive();     boolean isAttachedTo(LifecycleOwner owner) {         return false;     }     void detachObserver() {     }     //是否活跃状态变化     void activeStateChanged(boolean newActive) {         if (newActive == mActive) {             return;         }         //修改是否活跃         mActive = newActive;         //判断活跃的观察者数量 见分析5         changeActiveCounter(mActive ? 1 : -1);         if (mActive) {             //当是活跃时分发事件             dispatchingValue(this);         }     } } 复制代码

先继续分析3的来说,这里是如何判断是否还是活跃,就看其实现类了:

//实现类,且实现了LifecycleEventObserver接口,用来接收Lifecycle的事件 class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {     //生命周期持有类,也就是Activity/Fragment     @NonNull     final LifecycleOwner mOwner;     LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {         super(observer);         mOwner = owner;     }     //当Lifecycle的State在STARTED以及以上才是活跃     @Override     boolean shouldBeActive() {         return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);     }     //Lifecycle的事件变化     @Override     public void onStateChanged(@NonNull LifecycleOwner source,             @NonNull Lifecycle.Event event) {         //当前Lifecycle的状态         Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();         if (currentState == DESTROYED) {             //当是DESTROYED时移除观察者             removeObserver(mObserver);             return;         }         Lifecycle.State prevState = null;         while (prevState != currentState) {             prevState = currentState;             //active状态发生变化             activeStateChanged(shouldBeActive());             currentState = mOwner.getLifecycle().getCurrentState();         }     }     @Override     boolean isAttachedTo(LifecycleOwner owner) {         return mOwner == owner;     }     @Override     void detachObserver() {         mOwner.getLifecycle().removeObserver(this);     } } 复制代码

由上面代码的onStateChanged可以看出LiveData的又一个重要特性:当观察者对应的Lifecycle的生命周期状态是DESTROYED时将自动移除该观察者

同时会调用父类的activityStateChanged方法来设置活跃程度,也就是一般而言生命周期在STARTED以及以后的值。

分析5:在抽象类的activeStateChange代码中有个关键地方,当mActive为true时,他会去分发值,然而这个方法的调用会在生命周期变化时调用,所以可以得到LiveData的一个重要特性:当观察者对应的生命周期发生变化时,由不活跃变成活跃时,将通知分发LiveData保存的值,这也就是当界面重新可见时会自动刷新在可见之前保存的值

分析5部分代码还调用了一个判断活跃观察者数量的方法:

//判断活跃观察者数量 void changeActiveCounter(int change) {     int previousActiveCount = mActiveCount;     mActiveCount += change;     if (mChangingActiveState) {         return;     }     mChangingActiveState = true;     try {         while (previousActiveCount != mActiveCount) {             boolean needToCallActive = previousActiveCount == 0 && mActiveCount > 0;             boolean needToCallInactive = previousActiveCount > 0 && mActiveCount == 0;             previousActiveCount = mActiveCount;             if (needToCallActive) {                 //当有活跃观察者时                 onActive();             } else if (needToCallInactive) {                 //当没有活跃观察者时                 onInactive();             }         }     } finally {         mChangingActiveState = false;     } } 复制代码

这里的onActive和onInactive是LiveData的方法,这个在后面自定义LiveData时有关键作用,可以释放一些资源。

上面其实是分析3的衍生,说明了如何判断观察者是否活跃以及实现方法,继续看一下分析4处的代码,在 considerNotify注释中。

分析4:既然可以通过mActive可以判断是否活跃,为什么还要调用一次shouldBeActive呢,原因非常简单在上面我们分析过observer在收到Lifecycle的状态变化时才去更新mActive,但是当Event还没有获取到时,这时就有值需要去分发,这时就要手动调用这个方法去判断,进一步确保代码正确性。

子线程修改数据

上面代码说了主线程修改数据、通知观察者以及判断观察者是否活跃的流程,里面会发现有很多特性,接着我们来看一下子线程修改数据以及多线程数据同步如何实现。

//子线程调用 protected void postValue(T value) {     //处理快速修改情况 见分析1     boolean postTask;     synchronized (mDataLock) {         //上锁,mPendingData保存value 见分析2         postTask = mPendingData == NOT_SET;         mPendingData = value;     }     if (!postTask) {         return;     }     //主线程执行runnable     ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); } 复制代码

//锁 final Object mDataLock = new Object(); 复制代码

//volatile修饰的变量 volatile Object mPendingData = NOT_SET; 复制代码

//主线程运行的逻辑 private final Runnable mPostValueRunnable = new Runnable() {     @SuppressWarnings("unchecked")     @Override     public void run() {         Object newValue;         synchronized (mDataLock) {             //锁住同一个对象 见分析2             newValue = mPendingData;             mPendingData = NOT_SET;         }         //主线程分发数据         setValue((T) newValue);     } }; 复制代码

//主线程分发值,上面已经说过 protected void setValue(T value) {     assertMainThread("setValue");     mVersion++;     mData = value;     dispatchingValue(null); } 复制代码

这里可以发现它实现多线程同步的方式有一点不一样,并没有把某个 setValue(假设设置值) 的方法设置为同步的,而是仅仅锁了2个代码块,我们来分析一下。

分析2:在主线程的postValue中和和主线程的runnable中都对mdDataLock进行了锁,说明给mPendingData赋值和取出mPendingData是多线程同步的,而这个mPendingData也就负责线程之间的数据传递,所以就达到了线程同步的要求。

但是对于getValue方法也就是获取LiveData的值的方法如下:

//获取保存的值,非同步方法 public T getValue() {     Object data = mData;     if (data != NOT_SET) {         return (T) data;     }     return null; } 复制代码

这里却不是个同步方法,原因非常简单:

private volatile Object mData; 复制代码

mData是线程透明的,它是用volatile修饰的,所以只需要保证多线程赋值是同步的即可,而且实际情况是通过锁一个对象来间接实现赋值同步的,不用同步整个方法,这也是设计的巧妙之处。

分析1:在分析1处有个psotTask标志位,这个标志位十分重要,当发现主线程还没有处理mPnedingData时,将不再向主线程从新发送runnable,这个也非常好理解,因为主线程要干的事非常多,假如该子线程不断的发送值,如果不做处理将不停地给主线程发runnable,而主线程要等待到才会去处理,这就可能导致延迟性。

所以这里又算是LiveData的一个特性:当一个子线程不断的postValue时,在主线程没有处理完之前,只会去分发最新的值

添加观察者

上面说完了修改值时如何通知观察者,那就还剩一个主要内容便是添加观察者,代码如下:

//主线程 @MainThread public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {     assertMainThread("observe");     //当是DESTROYED状态时,直接无法添加     if (owner.getLifecycle().getCurrentState() == DESTROYED) {         // ignore         return;     }     //包裹一层,实现了Observer和LifecycleEvent2个接口     LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);     //添加到链表中     ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);     //已经有的话 直接报错     if (existing != null && !existing.isAttachedTo(owner)) {         throw new IllegalArgumentException("Cannot add the same observer"                 + " with different lifecycles");     }     if (existing != null) {         return;     }     //给Lifecycle添加观察者     owner.getLifecycle().addObserver(wrapper); } 复制代码

添加观察者代码非常简单,核心就是包裹类,把Observer和LifecycleEventObserver给结合起来,把这个wrapper添加给Lifecycle,当Lifecycle生命周期变化时,会通知wrapper,这里代码不用多说了。

到这里,LiveData这个类的代码我们说完了,但是相关知识还没有结束,我们后面继续。

总结

本章内容主要是介绍LiveData的原理,其中包含了很多LiveData的特性实现,都有用加黑字条表示,但是LiveData的知识还不止如此,比如如何转换LiveData、MediatroData如何使用、KTX包中有什么新扩展之类的,这些内容我们下篇文章继续分析。


作者:元浩875
链接:https://juejin.cn/post/7054384684536594446

文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐