Jetpack源码 之 LiveData
Jetpack源码 之 LiveData
0. 前言
LiveData是Jetpack中一个响应式开发框架,官方文档对它的说明是一种可观察的数据存储器类,具有生命周期感知能力。有点类似于感知生命周期的RxJava。
0.1 用法
通常LiveData都是结合着ViewModel使用的,一般都是在ViewModel中创建LiveData:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class MvvmViewModel : ViewModel() {
    // 通过MutableLiveData创建一个可读可写的LiveData
    // 设置为Private,避免外部对数据直接进行修改,并暴露对外接口,让外部通过接口来修改
    private val _count = MutableLiveData(0)
    // 暴露给外部一个只读的LiveData副本,让外部监听数据通过此LiveData监听
    val count: LiveData<Int>
        get() = _count
    fun increaseCount() {
        _count.value = _count.value?.plus(1)
    }
    fun clearCount() {
        _count.value = 0
    }
}
0.2 源码
LiveData源码其实挺简单的,但是在看他的源码之前得先了解Lifecycle的源码,因为LiveData其实是大量通过Lifecycle实现的。关于Lifecycle的源码我们之前看过了,所以此篇博客不会讨论Lifecycle的相关问题。
我们在阅读源码前,首先得清除我们需要从源码里面搞懂哪些问题:
- 首先,我们在用法上有MutableLiveData和LiveData, 那么他们的区别是啥
- 官方给LiveData定义是一个可被观察的数据存储类,那么他的可被观察是怎么实现的
- 官方还说他是生命周期感知的,那么是怎么实现的
带着这三个问题,我们来看源码:
1. MutableLiveData
这个类是我们用来可读可写的LiveData,我们对值的修改都是通过这个类的,那我们来看下他的源码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public class MutableLiveData<T> extends LiveData<T> {
    public MutableLiveData(T value) {
        super(value);
    }
    
    MutableLiveData() {
        super();
    }
    
    public void postValue(T value) {
        super.postValue(value);
    }
    
    public void setValue(T value) {
        super.setValue(value);
    }
}
源码就这么点,全是调用父类的方法,而他的父类就是LiveData类。
那么既然这些方法都是调用的LiveData的,那么为什么我们不直接使用LiveData而要去使用MutableLiveData呢?
当你看到LiveData源码时就能知道,LiveData虽然有这些方法,但是他是一个抽象类,没办法直接构造对象,所以我们就需要通过MutableLiveData来操作。
同时,LiveData的setValue()和postValue()方法都是被protected修饰的,所以我们在外部并没有办法直接访问到,而MutableLiveData的这两个方法是public的,所以可以在外部直接调用。
2. LiveData
2.1 基本属性
| 1 | public abstract class LiveData<T> { | 
这个代码很简单,增加版本、更新数据、分发事件。
因为这个方法只能在主线程中被调用(@MainThread),所以实现才这么简单,不需要考虑线程同步啥的。
2.3 LiveData # postValue()
| 1 | protected void postValue(T value) { | 
postValue会比setValue复杂一点,因为我们可以从最后一行看出,postValue是提供给我们在其它线程中调用的,然后调用之后他就会通过线程池传回主线程,再在主线程中更新数据并调用setValue。
那么为什么会需要mPendingData这个中间量呢?
原因也很简单,因为我们最终是要在主线程中调用setValue的,那么我们怎么把最新的值传递给setValue呢,况且这块还涉及到了线程切换,所以我们就必须通过一个中间变量来将这个数据从子线程传输到主线程了。并且由于为了避免多线程情况下对数据进行修改造成数据混乱,所以才对mPendingData加了锁,并且还在postValue处如果数据还没更新的话,后面来的数据都直接丢弃了。
2.4 LiveData # observer()
上面说到了设置数据,那么我们数据设置之后谁来相应呢?
我们在使用的时候都是通过observer方法来注册观察者的,那我们就看下这个方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26// 只许主线程中调用
public void observe( LifecycleOwner owner,  Observer<? super T> observer) {
    assertMainThread("observe");
    // Activity和Fragment都实现了Owner接口,所以这个Owner就相当于他们
    // 当他们的状态是DESTROYED时,代表刚创建或者要摧毁了,此时就不需要注册了
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    // 构造一个LifecycleBundleOvserver
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    // 存入mObservers这个map中去
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    // 如果已经存在了,并且他的owner并不是我们调用这个方法时传入的owner,就抛出异常
    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方法的源码很简单。
先根据传入的owner和observer构造一个LifecycleBoundObserver,然后把他们存入到mObservers这个SafeIterableMap中去,然后在存的时候,如果原本就有值,并且这个的owner还不是我们这次传入的这个owner,就抛出异常,如果原本有值,那么就直接返回,也就不存了。然后最后还是调用Lifecycle的addObserver存入到Lifecycle中去。
2.5 LiveData # dispatchingValue()
| 1 | void dispatchingValue( ObserverWrapper initiator) { | 
2.6 LiveData # considerNotify()
| 1 | private void considerNotify(ObserverWrapper observer) { | 
3. LifecycleWrapper
3.1 LifecycleWrapper
| 1 | private abstract class ObserverWrapper { | 
3.2 LifecycleBoundObserver
| 1 | class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver { | 
4. 总结
4.1 总结和流程
LiveData主要由2个类构成:
- LiveData:抽象类,实现类就是- MutableLiveData,只不过- MutableLiveData中的所有的方法都是直接调用了- LiveData的方法,本质上和- LiveData没啥区别。
- LifecycleWrapper:抽象类,主要用来对- Observer和- Version、- Active进行管理,而我们使用的都是- LifecycleBoundObserver,这个类继承自- LifecycleWrapper,并实现了- LifecycleEventObserver接口。
并且底层还是通过Lifecycle去实现的,就是对Lifecycle进行了一下封装。
LiveData的操作主要分为两种:
- 添加观察者:observer()
- 设置数据:- setValue()
- postValue()
 
4.1.1 添加观察者
- 调用observer()方法,- 在这个方法中会先构造一个LifecycleBoundObserver的对象,这个对象保存了这个mObserver以及激活状态mActive;
- 接着把这个对象通过mObservers.putIfAbsent()添加到mObservers这个map中去;
- 并调用owner.getLifecycle().addObserver(wrapper)添加到Lifecycle中进行监听。
 
- 在这个方法中会先构造一个LifecycleBoundObserver的对象,这个对象保存了这个
- 之后每当owner生命周期变化时,就会调用LifecycleBoundObserver的onStateChanged()方法 (具体可见Lifecycle的源码)- 如果当前owner的状态为DESTROYED的时候,就会将这个observer从mObservers中移除
- 如果不是,就调用activeStateChanged()去更新mActive
 
- 如果当前
4.1.2 设置数据
- postValue():这个方法主要是提供给我们在非主线程中去调用的- 这个方法中会先加锁,然后将数据保存到mPendingData中,并根据mPendingData的值判断上次post的值是否更新到mData中了:- 如果更新到了,则通过ArchTaskExecutor将mPostValueRunnable这个Runnablepost到了主线程中执行- mPostValueRunnable中会将加锁,将- mPendingData中的值更新到- newData中,并将- mPendingData值设置为- NOT_SET,然后会调用- setValue(newData)
 
- 如果没有更新,则会直接return退出这次postValue(),不更新数据,直接丢弃
 
- 如果更新到了,则通过
 
- 这个方法中会先加锁,然后将数据保存到
- setValue():这个方法只能在主线程中调用- 他就会直接调用dispatchingValue(null)进行分发
- 这个方法中如果传入的是null,就代表需要分发给所有的Observer,那么他会遍历mObservers,对每一个Observer调用considerNotify(iterator.next().getValue());
- 在considerNotify(observer)中会先判断传入的这个Observer的mActive是否为false,如果是的话,就代表没有激活,也就是他的owner处于STARTED之后,就没有必要去更新View了;而如果不是就继续往下执行:- 先调用shouldBeActive判断owner是否处于STARTED之后,如果是就调用activeStateChanged(false)去更新mActive为false,并return,不分发事件
- 在判断observer的mLastVersion是否大于当前的mVersion,如果大于等于,则也没有必要继续分发
- 之后更新observer的mLastVersion为当前的mVersion
- 调用observer.mObserver.onChanged((T) mData);去执行我们实现的Observer
 
- 先调用
 
- 他就会直接调用
4.1.3 流程图
对于流程我们可以用下图表示:
4.2 LiveData真的可以被用于事件分发吗
LiveData本质上是可观察的数据存储类,但是可观察这个特性不就可以被用来事件分发吗(EventBus),而且还通过Lifecycle实现了生命周期感知,这些相对来说比EventBus更加简单。
但是LiveData真的有表面上看上去的这个简单吗?真的有这么好吗?
4.2.1 postValue 数据丢失
在postValue方法中,如果mPendingData == NOT_SET的话,就会直接丢弃调这次的数据。也就是说,如果上次的事件还在分发,还没完成的话,那么这次的事件就会直接丢弃。
这样就导致了事件丢失。
4.2.2 considerNotify 不回调观察者
除了postValue存放事件这块有问题,considerNotify通知事件也有问题。
considerNotify这个方法第一行就是如果Observer处于非激活状态(mActive == false),那么这个时候他就不会回调这个Observer去分发事件。
只有当Observer处于激活状态,他才会进行分发。
这样就造成了事件丢失,中间传输的数据都无法收到。
4.2.3 LiveData本来就不是为事件分发打造的
在官方文档上第一句话就表明了,LiveData只是一个可观察的数据存储类,他的核心在于他能将最新的数据通知给观察者,也就是说,他本来就不会在意中间状态,它只要保证当View处于激活状态能得到最新的数据保证UI时正确的就行,如果还要去纠结中间状态的话,那么UI展示岂不会变得很奇怪;并且如果对于没有显示的View都要去通知这个View的话,这样不就会显得很多此一举。








