最近公司项目不忙,抽时间把LiveData的源码撸了两边,每撸一次,印象就深刻几分,整体的思路就更加的清晰了,越发的觉得LiveData的源码真的很简单~
一、源码分析
注:使用的livedata和viewmodel的版本为2.2.0
我们在使用LiveData的时候,通常和ViewModel配合来使用。在ViewModel中创建LiveData对象,使用ViewModelProvider创建ViewModel,Owner对象相同,就保证了ViewModel是相同的对象,那么LiveData对象就是相同的,就可以进行数据的监听了,关于LiveData的使用,可以上官网去摸索,这里我们只撸源码。
其实LiveData也不一定非要和ViewModel配合使用,比如LiveDataBus。因为官网的示例中和ViewModel配合使用了,所以我们也正好看一下ViewModel的源码
LiveData的使用分了三步:(1)获得ViewModel对象(2)注册 (3)数据发送
源码的分析我们也从这三步来撸
1.获取ViewModel对象
MessageListViewModel viewModel = new ViewModelProvider(this).get(MessageListViewModel.class);
MessageListViewModel是我创建的ViewModel类,这里用到了ViewModelProvider的两个方法,一个构造方法,一个get方法
我们想看一下构造方法
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
构造方法比较简单,主要对mFactory和mViewModelStore对象进行了初始化赋值。
mFactory:工厂类,从名字上我们可以猜测出主要是用来进行创建对象,所创建的对象正是ViewModel对象,这里mFactory正是通过NewInstanceFactory.getInstance赋值的
mViewModelStore:存储类,从名字上我们也可以猜出,主要是用key来存储ViewModel的,ViewModelStore的内部就是一个HashMap,同学们可以自己点击去看看,很简单。
mViewModelStore是owner的调用getViewModelStore来获取的,我这里的owner其实就是Activity对象,而Activity的父类是ComponentActivity,也就是说ComponentActivity实现了getViewModelStore方法,创建了mViewModelStore对象。自己点进源码看吧,超简单的,就是对mViewModel进行了创建
我们再看一下get方法
private static final String DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey";
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
if (mFactory instanceof OnRequeryFactory) {
((OnRequeryFactory) mFactory).onRequery(viewModel);
}
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
首先modelClass通过getCanonicalName方法拿到了ViewModel的全类名,然后和DEFAULT_KEY组成了一个新key,从mViewModelStore中进行查找,是否已经有此类了。如果有并且不为空,则返回此对象;否则,我们通过mFactory的create方法进行ViewModel对象的创建,而这个mFactory是NewInstanceFactory,所以我们看一下NewInstanceFactory中的create方法
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
使用了newInstance创建了ViewModel的对象
ViewModel对象的获取就这些东西,so easy~
2.注册(observer方法)
viewModel.userPagedList.observe(this, new Observer<MessageListBean.DataBean>() {
@Override
public void onChanged(MessageListBean.DataBean dataBean) {
}
});
userPagedList是我在ViewModel中创建的LiveData对象,MessageListBean.DataBean是被监听的数据。我们直接进入LiveData中的observe方法
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
//如果当前状态时销毁状态,那么直接返回
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
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;
}
owner.getLifecycle().addObserver(wrapper);
}
如果当前owner的状态时销毁状态,那么直接阻断返回
我们看到LifecycleBoundObserver这个类,从这个类的命名wrapper上可以看出来,LifecycleBoundObserver这个类其实就是一个包装类,它接收了owner和observer两个参数,我们进入查看一下它的源码
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
接口LifecycleEventObserver:这个类只有一个待实现方法onStateChanged。很明显,从名字上我们就可以猜测是owner生命周期变化时,会执行这个方法
父类ObserverWrapper:防止内容太乱,这个类我就不贴出来了,就在LifecycleBoundObserver的下面。内容不多,很易懂。我们上面实现的Observer类方法就会保存在这里。这个类中还有一个mActive属性,当它变为true的时候,表示owner处于活跃状态,那么就会通过这个类进行事件的分发,执行Observer的onChange方法。其中还有一个mLastVersion需要注意,这是一个标识,LiveData类中有一个mVersion属性,数据每发送一次,mVersion就会进行加1。如果mVersion比mLastVersion大,才会执行onChange方法。所以想要改变LiveData类似于粘性的特征,可以从这个mLastVersion属性入手,hook进行改变
LifecycleBoundObserver:owner会被保存在这里,owner的状态的变化会在这里获取到,从而传递给父类ObserverWrapper进行事件的分发。如果owner的状态变为不活跃是,Observer的移除也是在这里
我们回到LiveData的observer方法中,可以看到:observer为键,wrapper为值,存到了mObservers这个map中,随后进行addObserver进行了绑定。
mObservers这个类是一个map,当事件被触发需要进行发送的时候,就是遍历这个类,进行onChange
本来想画一张流程图的,但是这个流程简单到我不想画...
3.数据发送(setValue方法)
postValue方法我不去过多的描述,和setValue的区别就是线程调度,最终还是会回到setValue方法中来,我们看一下setValue方法
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
mVersion属性进行了加1,mData复制为要发送的value值,然后执行dispatchingValue方法,我们看下这个方法:
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;
}
因为形参initiator是null,所以对mObservers执行了遍历,mObservers的value是ObserverWrapper,随后调用了considerNotify方法,我们看下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;
observer.mObserver.onChanged((T) mData);
}
首先进行了owner状态的判断(上面简单的描述过),之后进行了version的比较(这个上面也说过),随后执行了onChange方法,到此结束。
整个事件分发的过程就是这么简单。但是还没有结束,还有很多问题我们都没有进行描述,我们继续往下看
二、问题
1.LiveData是如何与Activity和Fragment进行生命周期绑定的?
我们以Activity为例。其实上面也简单说过,Activity生命周期的变化会通过调用LifecycleEventObserver接口的onStateChanged方法通知到LifecycleBoundObserver,具体的流程是怎么样的呢?我们先用语言简单描述一下,再通过流程图来理解
所有的一切都是从LifecycleRegistry开始的,无论是Activity,还是Fragment都有LifecycleRegistry对象的创建,从名称上我们知道,这个是生命周期的一个注册器。Activity的生命周期的改变,会调用到LifecycleRegistry的handleLifecycleEvent方法(整个过程我是倒着找到,所以能找到这个方法),而Activity的生命周期的变化通知是父类FragmentActivity中进行的,点击handleLifecycleEvent方法就可以发现,上图
2.如果ActivityA中对一个事件进行了监听,ActivityB中也进行了此事件的监听,在ActivityA中对事件进行setValue,此时如果跳转到ActivityB中,为什么也能收到相应事件的改变?(类似粘性)
估计用过LiveData的同学都知道上述的问题,那是什么原因导致LiveData在进行事件传递的时候有这种粘性特征呢?
如果理解了上述流程图的话,估计这个问题就已经明白了。因为每次生命周期的改变都会执行onChange方法,如果你在Activity的onCreate方法中注册,那么当Activity变为活跃状态时,就会执行onChage方法,从而实现了类似于粘性特征的功能。如果不想使用这种粘性特征怎么办?上面我提到过,通过hook的方式来改变mLastVersion的值,具体的办法可以百度一下,有很多的~
3.LiveData中,在执行onChange方法前,为什么要做mVersion的比较?它的作用是什么?
因为Activity每次进行生命周期改变的时候,都会执行onChange方法,而mVersion执行在发送数据的时候才会加1。通过mVersion的比较,可以防止生命周期变化时,多次执行onChange方法