LiveData的主要作用是可以通过观察者模式进行异步的通知,我们使用它的主要场景就是把网络数据,数据库数据等通过异步的方式通知UI。他的优点是可以避免内存泄漏,与生命周期关联起来,回调也是在主线程中。
使用
我们一般会把LiveData结合ViewModel一起使用,ViewModel作为桥梁,LiveData就是当中的运输数据的工具,与DataBinding中的ObserverField类似。
1 | //SettingViewModel |
与我们平时使用回调的方式是不太一样的,我们只需通过LiveData的observe
方法即可监听到请求的返回结果,该方法的参数一个是LifecycleOwner,通过该参数LiveData可以获取到Lifecycle然后监听生命周期,另外一个是Observer
接口,监听他就可以收到LiveData传递回来的参数。
源码解析
LiveData是一个抽象类,我们一般使用的是MutableLiveData,他的实现类,MutableLiveData与LiveData的区别只是它把LiveData的setValue和postValue方法改为了public
而已。
LiveData通知数据更新主要有两种方式,一种是postValue
,另外一种是setValue
,他们二者的区别是前者可以在任意线程进行调用,后者是必须在主线程调用。
然后他的观测数据变更方法也是有两个,一个是observe
,另外一个是observeForever
,他们二者的区别后面再细说,需要知道的是我们监听数据的回调,也就是Observer
的接口实现方法的回调都是在主线程的。
LiveData是一个泛型类,声明是LiveData<T>
,我们先分析它的成员变量
- mDataLock,同步锁,使用在那里后面说
- mObservers,他是
SafeIterableMap<Observer<? super T>, ObserverWrapper>
类型,关于该类型可以看Jetpack之FastSafeIterableMap源码,用于存储所有的观察者对象 - mActiveCount,记录激活的次数
- mChangingActiveState,用于判断是否正在调用
changeActiveCounter()
方法,该方法作用后续再说 - mData,需要更新的数据,只记录最后一次需要更新的数据
- mPendingData,用于标识当前需要处理的数据,然后判断是否需要进行数据更新
- mVersion,相当于LiveData数据更新的次数或者是版本
- mDispatchingValue,用于判断是否正在更新通知回调
- mDispatchInvalidated,用于判断是否需要继续通知回调,与mDispatchingValue结合使用
- mPostValueRunnable,用于异步更新时候的Runable对象
- NOT_SET,默认的mPendingData值,等于该值的时候表明不需要进行数据分发
12,START_VERSION,LiveData的默认开始版本值
然后是LiveData的构造函数
1 | public LiveData(T value) { |
我们先分析一下LiveData如何添加一个Observer的过程,先分析observe
方法,平常使用它的频率也较高
1 | @MainThread |
这个过程就是把我们的Observer对象存入mObservers中,存入的过程把它包装了一些,与Lifecycle比较的类型。其中ObserverWrapper也是一个抽象类,LifecycleBoundObserver实现了它并且可以根据生命周期判断是否需要通知观测者。
1 | private abstract class ObserverWrapper { |
然后我们看与生命周期关联的LifecycleBoundObserver
1 | class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver { |
经过这个过程分析,我们可以知道,使用observe
进行观测的Observer的回调被调用只会发生在onStart,onResume,onPause
中,那么是否那些在onCreate,onstop
进行通知的事件是否Observer将不会知道呢,我们接着看他的,首先是changeActiveCounter
方法
1 | @MainThread |
接下来是核心的数据更新通知方法
1 | void dispatchingValue(@Nullable ObserverWrapper initiator) { |
然后看最终通知Observer的considerNotify
方法
1 | private void considerNotify(ObserverWrapper observer) { |
这就是整个流程了,我们再梳理一次:对于使用observe(LifecycleOwner owner,Observer<? super T> observer)
注册的Observer而已,通知的执行顺序是(暂不考虑setValue的):
1 | 1. 当声明周期发生变化,会调用LifecycleBoundObserver的onStateChanged,假如生命周期组件已经DESTROYED了,则把该Observer从观察者mObservers中移除,否则调用activeStateChanged更改自身的激活态变量 |
这就是大体的数据更新通知流程,然后我们看除了生命周期变化会触发通知以外,还有postValue(T value)
和setValue(T value)
,前者最终是通过Handle调用了后者,我们先看前者
1 | protected void postValue(T value) { |
通过这个方法我们知道假如说同时调用了多次postValue(value),那么他只会记录最后一次的value,然后使用这个value去分发,然后我们看mPostValueRunnable
1 | private final Runnable mPostValueRunnable = new Runnable() { |
然后我们看setValue
1 | protected void setValue(T value) { |
这就是整个数据外部更新的过程。
然后我们来思考一个问题,假如我们的Activity处于onStop/onCreate阶段,外部调用了setValue或者是postValue,这时候会发生什么情况
- 首先,我们的Observer不会立即接收到数据,因为这时候是处于非激活态
- LiveData的mVersion会+1
- 假如说我们的Activity执行到onStart,onPause,onResume,这时候会触发LifecycleBoundObserver的onStateChanged方法,然后把Observer设置为激活态
- 触发之后他会调用数据通知,数据通知的时候我们的Observer的mLastVersion是小于LiveData的mVersion,所以这时候才会去通知Observer
通过上面流程我们得到,使用了observe
方法注册的Observer,他在页面处于onCreate,onStop
的时候是不会接受到数据更新的,只有onStart,onPause,onResume
才会,这是我们使用注意的点。
还有一点就是我们的LiveData构造函数是带有一个默认值的,这时候我们先生成了LiveData,然后再去注册Observer,改Observer是否会接受到通知呢?答案是能?因为我们使用了LifecycleBoundObserver,他注册了之后Activity会自身的状态给它。即调用它的onStateChanged方法。所以假如我们的LiveData有默认值,那么每一个新注册的Observer都会被调用一次(激活态的时候,就算当时不是,后续转为激活态也会调用)
那有没有即时接受到数据更新的Observer呢?有,就是使用我们的observeForever(Observer<? super T> observer)
,
1 | public void observeForever(@NonNull Observer<? super T> observer) { |
可以看到他是使用了AlwaysActiveObserver,而且是立马就会同步当前的LiveData的数据给该Observer,我们看下AlwaysActiveObserver的代码
1 | private class AlwaysActiveObserver extends ObserverWrapper { |
这就是可以立即收到数据更新的Observer了,我们再看下其他的源码,
1 | //移除单个Observer |
这就是LiveData的整体源码分析了。
数据倒灌和EventBus
我们通过上面的源码分析,发现可以把LiveData改造成简单的EventBus,或者是总数据源。比如我们有这样的一个需求,我们有一个用户信息,他是全局的,很多的Activity都会使用到,同时假如用户信息更新了,我们的Activity也需要知道,这就可以利用LiveData进行处理。关于他的好处可以看Android消息总线的演进之路:用LiveDataBus替代RxBus、EventBus
由于我们的LiveData新增Observer的时候,他会把上一次的值通知给该Observer,即LiveData自动执行了一次setValue操作或者叫做发送了一次stick事件,这是不可以接受的,美团的解决方案是通过发生的方式,对于使用了observe
方法的,把所属的LiveData的mVersion字段赋值给该Observer的mLastVersion,对于observeForever
它将不会收到回调。
还有一种是继承LiveData,重写他的关键方法,具体可以看LiveData 数据倒灌,他给Observer添加一层限制来实现,使用HashMap<Integer, Boolean>
,当value为true的时候是不接受时间,false的时候接受,
1 | private void observe(@NonNull Integer storeId, |
上面两个方案的实现源码可以看:UnPeek-LiveData和LiveEventBus
我们可以使用一个全局的ViewModel,有一个LiveData变量承载用户信息。全局的ViewModel可以在Application创建一个ViewModelProvider然后去创建这个ViewModel。