LiveData是如何做到在合适的时机刷新的

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Kongou/article/details/82798451

项目的AAC框架改造也进行了一段时间了,对于谷歌新提出来的这一套JetPack框架,个人觉得还是相当不错的。好好使用,能够给开发带来很大的方便,对于以后的功能扩展也很有利。下面就来研究一下,JetPack中,LiveData是如何实现自动刷新的。

一、LiveData是什么

LiveData简单地说就是你的数据,只不过它会在发生变化时被监听到,从而根据它的变化做一些响应的处理,比如刷新UI等等。关于LiveData的详细解释可以参考官网,我之前的一篇文章中做了一部分介绍Android开发中AAC框架基础概念整理。这里就不多说了。下面准备好撸源码吧。

二、LiveData的setValue和postValue什么区别

使用过LiveData的朋友会比较熟悉,通常都会新创建一个类继承MutableLiveData,或者直接使用MutableLiveData把泛型替换成我们使用的数据类型。这个类中只提供了两个方法,比较简单,看看这两个方法在父类中是如何实现的。

setValue方法执行了上图中的四步。

第一行代码是判断当前线程是否是主线程,最终调用底层代码判断是否是主线程,如果不是则会抛出异常。

第二行是把整形变量mVersion自加。

第三行是赋值,把更新的数据赋值给mData。

第四行是分发事件。

这段才是setValue的核心。setValue里调用的时候,参数传的null。最外层的if-else判断看起来是像维护一个独立更新的状态,如果分发的时候,已经有分发事件在进行了,就会更新标志位mDispatchInvalidated 为true,什么都不做。如果没有更新,则会走另一个分支,我们注意到这里使用了do-while语句,表明至少要走一次do里面的事件。而initiator参数为null,所以直接看为null的分支。这里从mObservers里获取了一个迭代器的实现类,并且遍历迭代器从里面获取值,使用该值作为参数调用considerNotify方法。注意,这个iteratorWithAdditions方法是new了一个新类,这个类里维护了一个Observer与LifecycleBoundObserver的Entry。所以getValue时才能够强转为LifecycleBoundObserver。

来到considerNotify方法。可以看到先判断这个observer是否是active的状态。如果是,则继续判断这个observer的lifecycleOwner是否是Active状态。

可以看到,这里很巧妙地将几种状态以枚举类型的方式建立,使用时将当前状态与STARTED作对比,也就是说只有大于等于STARTED的状态才会被认为是active的。不满足这个条件,会被认为这个observer已经失效了,调用observer的activeStateChanged方法,传参为false。

我们看到,如果传参为false,之前本来是活跃的observer会把状态设为false。false状态下很多流程都不走了,只有当mActiveCount为0时也就是这个LiveData所绑定的observer全部都不活跃了,会调用onInactive方法。

如果是活跃的,则会判断mVersion这个参数是否大于上一次的参数。没错,这个就是之前执行自加操作的那个值。为了确保是更新过的,因为有时候你可以会set两遍同样的值。这时mVersion只要有变化,仍然会继续走一遍分发流程来保证你想要达到的效果。之后更新lastVersion的值为最新,同时调用observer的onChange方法并以value为参数。这个onChange方法就是我们创建与LiveData绑定的observer时需要重写的方法。

写到这里,observer是否活跃的状态很关键,为此,我们还需要看一下LiveData绑定lifeOwner和observer时的情况。post方法要放到后面在分析了。

三、LiveData的绑定

这段代码可以看出,绑定的owner不能是已销毁的。流程比较简单,根据owner和observer参数先建立一个BoundObserver类,之后判断这个observer是否已经存在,如果这个observer已经存在并且owner不一样的话,则会报错。不能把一个observer绑定到不同的owner上。如果不存在,则在owner里添加一个observer。(每个LiveData都维护了一个观察者map,这个map是以observer为key,BoundObserver为value。新版的Fragment实现了Lifecycle接口,里面维护了一个LifecycleRegistry,这里面维护了observer的集合。)addObserver添加,最终是添加到了LifecycleRegistry里。

之前写的时候,一直有个疑惑,就是setValue时,写入的是null。每次setValue一定会走mObservers.iteratorWithAddition这一步。再看看这个方法,实际上是以SafeIterableMap这个类里的mStart为值生成的一类,它里面的active不一定为null,实际上就是看mStart是什么。通过追踪代码发现mStart与这个map的put有关,从而想到绑定的时候可能会用到put。而事实证明在绑定的时候确实用到了put方法把observer放进了SafeIterableMap里。这下逻辑才对。一个LiveData可以维护多个observer,一旦发生setValue事件,就会从mStart开始,逐个遍历所有活跃的observer触发刷新事件。遍历方法在setValue里最后调用的dispatch方法里,有个while的循环,里面不断查看iterator是否有next。也就是从mStart开始直到next为空。(这块真的反复看了好久才看懂。)

这是addObserver方法,我们只看关键的一步,当添加observer顺利时,最终会调用statefulObserver里的dispatchEvent方法。

而这个方法最终调用了onStateChanged方法。

而这个方法是在LiveData里的LifecycleBoundObserver里实现的,有没有很眼熟。看不出来的朋友往上翻一翻哈。我们看到getCurrentState方法,这个是获取当前owner是否活跃。把结果传进isActiveState方法里。这里面才修改了observer的active状态,从而走分发流程。

我尼玛终于对上了。。。

也就是说,你new一个LiveData,调用setValue是可以设置值的,但是你想让它刷新,必须要绑定才生效。(想想也是)

四、继续postValue原理

如上图,mDataLock是一个Object类,专门用于锁控制的。NOT_SET也是一个Object类,是new出来的一个空的。看代码意思是说如果mPendingData为空,就允许执行postToMainThread方法。在看postToMainThread方法之前,先看看这个mPostValueRunnable是个啥。

登登登登,这货在LiveData构造方法里就初始化了。姿势已经帮你设计好了。里面同样考虑到了同步问题,如果没有锁竞争,则会正常执行,把mPendingData作为参数调用setValue方法。之后重置它为NOT_SET。整体的意思就是确保没有其他post执行的时候,才能执行它。接下来看看这个postToMainThread,看名字就猜到是放到主线程中执行。也就是执行UI相关操作。

连放三张图。postToMainThread方法调用的是mDelegate里的post方法,而这个delegate是默认为DefaultTaskExecutor这个类,这类里的postToMainThread方法显而易见,调用了Handler,这个Handler直接获取了主线程的Looper。通过主线程的Looper发的事件,最终会在主线程得到执行。其实底层是handler原理。

撸了一圈下来,终于搞懂了。我们调用的post方法最终是调用了handler在主线程发送事件。发送条件是lifecycleOwner要是活跃的,而且没有锁竞争存在。而post方法保证了在主线程环境后,最后还是调用setValue方法。而setValue方法想要触发刷新事件,必须要保证observer是激活状态(与owner实现了绑定)。也就是一切都是从LiveData的observer方法开始。

弄了一下午,终于搞定了。很累,但是感觉还不错。

猜你喜欢

转载自blog.csdn.net/Kongou/article/details/82798451