在之前学习MVVM的搭建的时候涉及到了LiveData这个可被观察的数据持有类,在ViewModel中使用LiveData封装数据确实能够为开发者提供了更高效的更新UI的方式。
LiveData最显著的两个特点:
- 基于观察者模式
- 同组件的生命周期绑定,能够及时的意识到组件的生命周期
关于结合LiveData搭建MVVM的方法移步这里
一. LiveData和MutableLiveData
MutableLiveData是LiveData的子类,MutableLiveData对外提供了两个方法:
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
postValue和setValue是LiveData提供的两种改变数据的方法,它们在LiveData中都是protected的,如果我们需要手动的设置数据,则需要将数据封装在MutableLiveData中。
在官方的文档中告诉我们postValue和setValue的区别在于:
- postValue():可以在主线程或者子线程调用,postValue会将任务发布到主线程以设置给定值。
源码如下:
protected void postValue(T value) {
boolean postTask;
//支持子线程中更新给定值的原因
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
//切换到主线程去执行任务
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
在postValue中给Object mDataLock加了锁,这样能够防止多个子线程对mDataLock进行操作,同时如果在主线程执行已发布任务之前多次调用此方法,则只发送最后一个值。这也是频繁调用postValue更新数据有可能会丢失数据的原因。
再看切换到主线程的Runnable:
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
setValue((T) newValue);
}
};
可以看到,其实在postValue中最后还是通过setValue来设置给定值。
- setValue():只能在主线程设置给定值,如果不在主线程调用setValue,会抛出异常。
源码如下:
@MainThread
protected void setValue(T value) {
//判断当前是否在主线程
assertMainThread("setValue");
mVersion++;
mData = value;
//分发给定值通知更新
dispatchingValue(null);
}
二.添加观察者
LiveData中为我们提供了两个添加观察者的方法,observe()和observeForever()。从源码来看看这两个方法之间有何不同。
- observe():
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// 如果组件处于未激活状态,则不做任何处理
return;
}
//将owner和observer对象封装成新的观察者对象
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//如果mObservers中已经存在观察者和wrapper的关联则返回,如果不存在,则关联并且返回null
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
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);
}
首先能够看出来,observe()也是必须在主线程中执行的。并且在observe中,observe是否执行是和组件的生命状态息息相关的。
observe里将onwer和observer封装成了一个新的观察者添加给Lifecycle,具体的逻辑在代码注释中已经写出,不做赘述。
- observeForever():
@MainThread
public void observeForever(@NonNull Observer<T> observer) {
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
//将活动状态设置为true保证无论如何都能通知数据的变更
wrapper.activeStateChanged(true);
}
从方法命名和代码能够看得出来,observeForever()和observe()最大的不同点就是observeForever不受组件的生命周期的限制,即使组件处于未激活状态,使用observeForever注册的观察者依旧会收到数据变化的通知。
从observeForever的参数列表和AlwaysActiveObserver的构造函数中也能够看出来,wrapper并没有将owner传入,所以观察者并不受组件生命周期的影响。
需要注意:由于使用observeForever()方法注册的观察者并不受组件生命周期的影响,所以不再需要使用观察者的时候需要手动的调用removeObserver()方法移除观察者。
三. dispatchingValue()数据变化消息的调度方法
之前在setValue()方法中,最后通过dispatchingValue()方法来通知观察者消息的变化,结合源码看看dispatchingValue究竟是怎么做到的。
private 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<T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
在setValue时,通过dispatchingValue(null)来实现数据变化的通知,从代码可以看出来,这个通知是通知mObservers容器中的对象,这个通知具体在considerNotify的方法里:
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
considerNotify方法首先会对当前组件的状态是否为最新状态进行判断,如果不是最新的状态,则不做任何处理,这样做是为了预防组件状态更新但没有收到事件的不稳定事件导致可能会发生无法预测的后续事件。
在看observer.mObserver.onChanged((T) mData);这句代码才是这个方法最主要的任务——通知观察者数据的变化。这里的onChanged其实就是重写的onChanged()方法。
结合之前写的MVVM的Demo来看看,整体的一个流程吧~(以refresh为例,为什么只需要设置一个isRefresh就能够直接更新User的信息), 看图说话~
refresh实现流程四. LiveData与组件的生命周期
LiveData同组件的生命周期绑定,能够及时的意识到组件的生命周期是LiveData的一大特点,在组件未激活的状态下LiveData不会将数据的改变通知给观察者,在组件DESTORY后LiveData会自动的清除观察者,在LiveData中肩负这个使命的是LifecycleBoundObserver,源码走起~
先看LifecycleBoundObserver的继承关系:
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver
ObserverWrapper在observeForever()中已经出现过了,LifecycleBoundObserver作为ObserverWrapper的子类,个性的部分就是对组件生命周期的监听。
GenericLifecycleObserver是一个继承自LifecycleObserver的接口(LifecycleObserver只是一个样本,并没有声明任何方法),GenericLifecycleObserver中声明了一个onStateChanged()方法,用于接收组件任何生命周期的更改并且发送给接收的一方。
再看看LifecycleBoundObserver的构造函数:
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {
super(observer);
mOwner = owner;
}
构造函数传入了一个LifecycleOwner,这个owner就是继承自LifecycleOwner的组件,通过owner可以获取到组件的状态。
接下来看看onStateChanged()方法的具体实现:
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
//DESTROYED状态移除观察者
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
//判断状态
activeStateChanged(shouldBeActive());
}
从代码中可以了解到,onStateChanged主要工作就是感知到组件状态的变化,最后将这个状态交给activeStateChanged处理(DESTROYED除外),再看看activeStateChanged的源码:
void activeStateChanged(boolean newActive) {
//新状态和之前的状态相同,不需要重复处理
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive; //更新状态
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
if (mActive) {
dispatchingValue(this);//任务处理,分发
}
}
在activeStateChanged中首先对新状态进行了判断以避免重复处理,之后将组件状态更新到最新。
mActiveCount用来记录组件存活的数量,这是因为同一个ViewModel可以被多个组件绑定。如果有存活的组件则调用onActive(),没有则调用onInactive(),这两个方法都是空方法,可以根据实际需求继承LiveData自己实现。
最后如果组件是存活状态,则通过调用dispatchingValue()进行事件分发。
五.总结
到这里LiveData的源码学习暂时告一段落,LiveData应用观察者模式保证了数据和UI的分离,是在学习观察者模式上实际应用中一个较好的参考例子。
相关笔记传送门:
MVVM设计模式学习笔记(一)——MVVM初体验
MVVM设计模式学习笔记(二)——结合LiveData来搭建MVVM
网友评论