本文内容:
- LiveData添加observer以及如何和LifecycleOwner的关联
- LiveData如何实现数据更新
- LiveData的其他问题
- 为什么在mPostValueRunnable中,明明是主线程,还要加synchronized
- 为什么dispatchingValue()要写的这么复杂
- 为什么在considerNotify()中要二次检查shouldBeActive()
类图
LiveData的类图比较简单,应该无需多做解释
LiveData添加Observer
- 判断是否是主线程,这点和Lifecycle就不一样,直接指定了只能在主线程中添加Observer
- 判断是否已DESTROYED,在onDestroyed()调用之后添加就没有用了
- 创建Observer的wrapper对象,类型为LifecycleBoundObserver,详细看UML类图,它不仅是ObserverWrapper,而且实现了LifecycleEventObserver
- 将wrapper对象push到mObservers中,也就是说LiveData和Observer是一对多的关系
- 将LifecycleBoundObserver对象加入到Lifecycle中,这一步会回调对应的生命周期方法
LiveData实现数据更新
LiveData的数据更新分为两种
- 生命周期触发数据更新,这是为了保持Observer的数据和LiveData中的一致
- 通过setValue()/postValue()主动更新数据
生命周期触发数据更新
由于将LifecycleBoundObserver加入到Lifecycle中,所以Activity的生命周期变化自然会触发LifecycleBoundObserver的onStateChanged()
方法
LifecycleBoundObserver.onStateChanged()
- 判断是否是DESTROYED,是则要移除对应的observer,否则可能会引起内存泄露,想象一下:屏幕旋转的情况,ViewModel未被销毁, ViewModel持有LiveData, LiveData持有Observer,Observer持有Activity
- 调用
activeStateChanged(boolean newActive)
,这里会传入shouldBeActive()
方法返回值,在LifecycleBoundObserver中,它指代的是当生命周期在onStart()调用之后onStop()调用之前的STARTED状态才会为true
ObserverWrapper.activeStateChanged()
- 如果已经新老状态相同,则直接返回
- 更新状态,获取当前是不是第一个更改的Observer
- 增加mActiveCount加一或减一,
- 如果是第一状态改变并且是mActive,则回调
onActive()
,另一个onInactive()
逻辑相似,从这可以看出mActiveCount的作用就是判断当前的observer是不是第一个active或者第一个deactive - 如果是新状态是STARTED之后,则调用
dispatchingValue(this)
,注意此时的参数
postValue()主动更新数据
postValue()
是异步更新,而setValue()
则是同步更新,setValue()
必须是在主线程调用,而postValue()
没有这个限制,根据文档postValue()
会比setValue()
晚更新(并且这个是跨生命周期的),具体的看Handler处理消息的机制。由于postValue()
最终也是调用到setValue()
,所以我们分析postValue()
即可
LiveData.postValue()
- 定义了postTask,注意postValue()可能会在多个线程中调用,postTask是线程私有的
- 给postTask赋值,这里我不是特别理解为啥mDataLock和mPendingData要用volatile标记,synchronized不是会取消缓存行吗?
- 更新mPendingData为post过来的value
- 如果postTask为false,则直接return,对于所有post的线程,我们只需最新的数据发送一次就可以了,不需要多余的更新
- 给主线程发送消息,在mPostValueRunnable当中
mPostValueRunnable.run()
- 先给newValue赋值引用,这里添加synchronized原因见问题1的答案
- 将mPendingData重置引用
- 调用setValue()继续更新数据
LiveData.setValue()
- 判断是否是在主线程,否则直接抛出异常
- 将数据的版本号+1,更新当前的value
- 调用
disPatchingValue(null)
,注意和ObserverWrapper.activeStateChanged()
中的调用的参数区别,这个很重要
LiveData.dispatchingValue()
- 如果正在分发,则先返回,并且将mDispatchInvalidated设置为true,这部分逻辑后面进行解释
- 如果是
ObserverWrapper.activeStateChanged()
调用则会传入ObserverWrapper对象,直接调用considerNotify()方法,这里注意initiator要重置为了null,原因后面再说 - 如果是
setValue()
调用,则对每一个Observer都更新其数据,调用considerNotify()
LiveData.considerNotify()
- 判断
observer.mActive
是否为true,也就是初步判断状态是否为STARTED,这步是为了setValue()而设计的,因为setValue()可能在任何地方调用 - 再次判断状态是否为STARTED,原因后面具体讨论
- 判断mLastVersion是否小于LiveData的数据版本,是的话,则调用Observer.onChanged(),但我觉得这里可以改成==,因为mLastVersion不会大于mVersion
LiveData数据最新保证
也就是LiveData要尽量保证mData是最新值,也要保证Observer.onChange()
最后一次的回调是最新的数据,为了这个条件也是费劲了心思,下面的问题答案都是为了这个前提
为什么在mPostValueRunnable中,明明是主线程,还要加synchronized
这里的原因是要等到postValue()中所有的线程都完成了pendingData更新,因为LiveData只需要最新的数据,其他中间数据都不关心
为什么dispatchingValue()要写的这么复杂
先说一下mDispatchingValue和mDispatchInvalidated,从字面意义上就比较容易理解这两个分别说的是正在更新值,以及需要刷新值。那么这两个变量有什么作用呢?
这两个变量最主要的作用就是在调用observer.onChange()
中又setValue()了,于是就出现数据更新了,那么如果此时没有这两个变量以及循环,我们来考虑一下状况:
setValue()调用,在某个observer.onChange()
中又调用了setValue(),假设为observer_1,那么就会出现observer_1之后的那些observer会出现连续调用两次considerNotify()并且两次都是第二次setValue()的值,这里需要想象一下链表的循环,这样虽然onChange()不会重复调用,因为有mVersion的存在,但是效率会降低,considerNotify()会被调用多次,这里只是举了两次的嵌套,可能还有多次嵌套
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
当出现嵌套setValue()的时候,假设还是observer_1好了,此时的逻辑如下
- mDispatchingValue由于为true,所以mDispatchInvalidated也设置了为true,直接return
- 此时回到了遍历的循环中的considerNotify()下一行,判断mDispatchInvalidated为true,跳出遍历循环
- while()的判断mDispatchInvalidated也是true,这是重新进行遍历更新数据,这样observer_1之后的链表就只会更新一次,observer_1之前的当然会出现两次更新,但是他们的数据不同,可以理解
当生命周期间出现嵌套setValue()的时候,initiator = null
就好理解了,假如出现了更新,直接将其转为setValue()类型的更新,
mVersion的作用
mVersion一个是上面所说的嵌套setValue()的时候防止onChange()多次调用,另外一个则是在刚刚添加observer的时候,想象一下:假如在onResume里面添加一个observer,生命周期驱动数据更新的时候如果没有mVersion的话,那么就会回调一个空指针
为什么在considerNotify()中要二次检查shouldBeActive()
这里也是嵌套的原因,比如在LifecycleObserver中的onStop()中调用LiveData.setValue()方法,此时LiveData的LifecycleObserver还没有回调到,应该就会出现这种情况
使用LiveData注意的事项
不要在onChanged()的调用中出现死循环,比如:无条件的setValue()