JetPack作为Google官方推荐的一套标准化开发套件,很值得去使用和学习。
这篇介绍LiveData
。LiveData
是一种可观察的数据存储器类。与常规的可观察类不同,LiveData
具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData
仅更新处于活跃生命周期状态的应用组件观察者。
基本使用
LiveData
本质是一个①遵循生命周期、②可供观察的存储类。
使用姿势1 | 使用姿势2 |
---|---|
乍一看和我们之前学的EventBus
、RxBus
之类的事件总线很像,不就是个观察者模式嘛。姿势2不就是反映出黏性的状态嘛。
事实也是如此。
不过它具有生命周期感知能力,LiveData
只会将更新通知给活跃的观察者。为观察 LiveData
对象而注册的非活跃观察者不会收到更改通知。
Google官方不建议我们这样直接在Activity中使用,而是将
LiveData
放在ViewModle
中,Activity中只负责监听及变化后的处理事件。以构建成MVVM架构。
源码解析
MutableLiveData
继承自LiveData
,直接看LiveData
的observe()
方法。
observe(owner,observer)
1 |
|
之前说过,LiveData
仅更新处于活跃生命周期状态的应用组件观察者,这里的活跃状态具体指的是START
和RESUME
。
首先是必须要在主线程执行,判断生命周期状态是否活跃;然后new一个LifecycleBoundObserver
命名为wrapper
,将其作为VALUE,以传进来的observer
为KEY,存入mObservers
中。
然后将wrapper
放入生命周期的监听中。wrapper实现了LifecycleEventObserver
接口,所以wrapper
放进去后接着就会调用wrapper
中的onStateChanged
方法【这一句内容属于Lifecycle
知识点,详见Lifecycle解析】。
wrapper.onStateChanged
1 |
|
判断了下生命周期是否活跃,然后走向了activeStateChanged( )
。
这里传入的布尔值是判断生命周期状态:当前状态在STARTED
之前,false; 在STARTED
状态之后,true。
说明只有在STARTED
和RESUME
状态时会传true进去,印证了之前说的 “活跃状态具体指的是START
和RESUME
。”。
1 | //这个方法是在抽象类`ObserverWrapper`中。 |
这个方法中,先将传进来的newActive
赋值给mActive
。
mActiveCount
表示活跃状态下 obs的数量;wasInactive
(为true)表示之前活跃状态下没有obs;
mActive
true表示当下处于活跃状态,并且你传给了我个obs;
所以mActive
为true的时候,mActiveCount
要+1;为false时,mActiveCount
要-1。注意这里mActiveCount
发生了改变!!
然后判断,
如果改变之前没有obs活跃 && 传来的obs即将变活跃,那就要onActive()
;
如果 改变之后依然没有obs活跃 && 传来的obs也不会变活跃,那就onInactive()
;
当然这两个方法都是空的,需要用户自己去写。
说人话就是:当活跃的数量0–>1时,执行onActive()
;由1–>0时,执行onInactive()
。
最重要的其实是下一句:如果现在是活跃状态,我收到了obs,所以要执行下一步操作了。
dispatchingValue(wrapper)
1 | void dispatchingValue( ObserverWrapper initiator){ |
这两个布尔值,emmm,看的有点绕。再看这个do while,这循环怎么这么怪?
1 | //第一次A,B = false |
WTF??一脸黑人问号?这种循环能跑到第二圈?这种循环要是能循起来,我当场把显示器吃掉!!
不管了,重点看do while中的代码,传进来wrapper是不为空的,走considerNotify
方法,
1 | private void considerNotify(ObserverWrapper observer) { |
一些列判断之后,如果未被return,则执行wrapper.mObserver.onChanged()
方法。
当然,第一次
observer.mLastVersion
和mVersion
都是初始值-1,所以不会执行到此。除非mVersion
变了…
大的流程走通了,再看看setValue方法。
setValue
1 |
|
**版本++**,存储data,然后再dispatchingValue(null);
。
等等,这里也进到了dispatchingValue
,也就是说dispatchingValue
中可能出现多个线程同时访问进去的情况。这样一来之前看不懂的那两个布尔值和一个长得奇怪的do while循环就说得过去了。
这种情况下,循环就循环起来了了。
咳咳,我们继续😂。dispatchingValue
方法中有一个针对null的判断,这时候传进来的initiator为空,走else的方法。把mObservers
遍历一遍,然后依次执行considerNotify(iterator.next().getValue());
。
如果大家记性不太好的话,我帮大家回忆一下:
1 | LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); |
所以getValue方法中得到的就是我们在observe方法中初始化的wrapper。
再看considerNotify
1 | private void considerNotify(ObserverWrapper observer) { |
这次进入这个方法的时候有一点不一样,我们在setValue方法中**版本++**了,所以这个时候mVersion大于mLastVersion了,这个时候才会执行observer.onChanged
方法。
mVersion
的意义就在这里体现出来了。
如果你先setValue(版本++),然后再observer(),onChanged
依然会被触发。这就是所谓的黏性事件。也就是说黏性是在源码中写死了的,不支持像EventBus那般可进行配置。你想不黏性都不行。
postValue
1 | protected void postValue(T value) { |
1 | private final Runnable mPostValueRunnable = new Runnable() { |
postValue也一样,通过一个mPostValueRunnable
,最后转到了SetValue方法。
总结
LiveData
的作用其实是事件的分发,其实现原理是基于发布/订阅者模式,但是LiveData和传统的EventBus、RxBus这类事件总线又不太一样。
Google对其在功能上加以限制,几乎只有set/post和observe这三个方法;而上述Bus框架理论上可以在代码的任意一处进行分发,在代码的其他地方进行任意调用,虽然灵活,但无形中增加了管理成本,尤其是当项目日益庞大的时候,若项目中的Bus管理不善,发送和接收的事件(event)将会泛滥成灾,造成不可预期的后果。
而LiveData,可以通过和ViewModle的配合,完美规避这些问题,使事件的传递更加纯粹 和 易于管理。
同时,LiveData
的生命周期感知能力也避免了由于生命周期的变化带来的内存泄露等问题。
当然,你也完全可以利用LiveData将其封装成LiveDataBus,实现相似的事件总线框架,但是这有违Google的初衷,Google开发团队的初衷是让我们使用LiveData+ViewModle的模式来管理数据,这才是Google团队认为的最佳做法。
最后,关于LiveData的粘性设计可能带来的BUG和解决方案,我会另开一篇文章详谈,不在此赘述。