上一篇文章解析了一下Lifecycle的源码剖析Lifecycle源码,因为Lifecycle的应用很广泛,而JetPack的一些其他组件也涉及到了Lifecycle,LiveData也不例外,所以就在第一个写了Lifecycle的文章,今天就来通过解析LiveData 的源码来了解其原理。
LiveData简介及基本使用
LiveData是谷歌开发的jetpack的一个组件,通过LiveData可以实现数据感知组件的生命周期,并且能在数据改变时通知那些监听了该该数据并且可见的组件。先来看看LiveData的基本用法:
LiveDala一般是配合ViewModel使用的,ViewModel不懂也没关系,并不影响阅读代码:
public class MyViewModel extends ViewModel {
private MutableLiveData<LDBean> ldBeanLiveData;
public MutableLiveData<LDBean> getLdBeanLiveData(){
if(ldBeanLiveData==null)
ldBeanLiveData = new MutableLiveData<>();
return ldBeanLiveData;
}
}
MutableLiveData是LiveData的子类,它的作用主要是向外界暴露setValue和postValue方法,可以在其他地方调用这两个方法来修改数据:
public class MutableLiveData<T> extends LiveData<T> {
public MutableLiveData(T value) {
super(value);
}
public MutableLiveData() {
super();
}
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
泛型用来接收数据类型,这里是LDBean类型,LDBean是一个实体类,只定义了一个属性id:
public class LDBean {
private String id;
public LDBean(String id) {
this.id = id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
而在activity中又是如何才能监听LiveData数据变化的呢?
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(MyViewModel.class);
viewModel.getLdBeanLiveData().observe(this, new Observer<LDBean>() {
@Override
public void onChanged(LDBean ldBean) {
System.out.println(ldBean.getId());
}
});
}
viewModel是MyViewModel的一个实例,viewModel.getLdBeanLiveData()就是viewModel的成员变量ldBeanLiveData,所以知不知道ViewModel都不影响阅读LiveData的代码。一旦ldBeanLiveData调用setValue或者postValue,只要activity是可见的(生命周期在onStart()之后onStop()之前),都会回调到这个匿名内部类Observer的onChanged方法:
viewModel.getLdBeanLiveData().setValue(new LDBean("1"));
viewModel.getLdBeanLiveData().postValue(new LDBean("2"));
不过setValue是在主线程调用的,而postValue是在子线程调用的。
这应该就已经知道了,实际上监听LiveData数据变化的并不是activity,而是这里的匿名内部类Observer,而LiveData又是如何做到感知activity的生命周期的呢?又是如何做到将数据变化通知给Observer的呢?接下来就进入源码仔细研究吧。
LiveData源码
先从LiveData的observe方法开始:
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
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);
}
注意这个方法只能在主线程中调用,入参为LifecycleOwner和Observer类型,这里的owner就是activity,observer就是之前的那个匿名内部类,这是一个接口,只有一个onChanged方法:
public interface Observer<T> {
void onChanged(T t);
}
LiveData的observe方法中首先会判断如果'owner'的生命周期为销毁状态,就直接return,否则会将owner和observer封装到一个LifecycleBoundObserver中去,先不看其他的,先看一下这个类的构造方法和成员属性:
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
}
这个类继承了ObserverWrapper实现了LifecycleEventObserver接口,看到这个就会想到Lifecycle,ObserverWithState中的成员变量mLifecycleObserver就是这个接口的实例,activity生命周期变化时就会调用到接口的onStateChanged方法,而这里应该也是这样,现在记住就行,后面还会再分析。成员变量mOwner就是activity,再看一下ObserverWrapper的构造方法:
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}
}
成员变量mObserver就是构造函数传入的,mActive标志了activity是否可见,具体如何赋值后面会说。mLastVersion表示了版本号, 先交代一下,后面再分析。
再回到LiveData的observe方法,新建了LifecycleBoundObserver对象wrapper以后,再将wrapper添加到mObservers中,mObservers是SafeIterableMap类型的对象,这是一个map结构,每一个元素有前驱结点和后继结点,这里就是一个观察者模式,wrapper作为观察者观察LiveData的数据变化,紧接着再做一些容错处理,最后再将wrapper加入到owner的lifecycle的观察者列表中,因为wrapper也是LifecycleEventObserver的实例,所以wrapper能够监听activity的生命周期变化。
到这里可以总结一下,调用了LiveData的observe方法后,首先会将传入的activity和observer封装成一个LifecycleBoundObserver对象,再让这个对象同时作为观察者观察LiveData的数据变化和activity生命周期的变化,也就是一个观察者同时观察两个被观察者。
下面就分析两个被观察者发生变化时是如何通知被观察者以及被观察者接收到通知以后又是如何工作的:
组件生命周期变化时观察者是如何工作的
从上一篇剖析Lifecycle源码中知道,当activity生命周期发生变化时,最终会调用LifecycleBoundObserver的onStateChanged方法:
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
当被观察者activity生命周期为destroyed的时候,会执行removeObserver方法,注意这个removeObserver方法是LiveData的方法:
@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
assertMainThread("removeObserver");
ObserverWrapper removed = mObservers.remove(observer);
if (removed == null) {
return;
}
removed.detachObserver();
removed.activeStateChanged(false);
}
这个方法只能在主线程调用,首先会将该观察者从LiveData的观察者列表中删除,再调用观察者也就是LifecycleBoundObserver的detachObserver方法:
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
就是将观察者从Lifecycle被观察者列表中删除,接着又会调用观察者的activeStateChanged方法,先交代一下,这个方法会在被观察的activity生命周期变化时被调用:
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);
}
}
mActive表示这个观察者是不是活动状态,当被观察的activity可见时(再强调一下:生命周期在onStart()之后onStop()之前的activiy是可见的),则该观察者是活动的,mActive的值为true,被观察的activity不可见则表示观察者是不活动的,mActive的值为false,第一个if表示,如果activity的可见性发生变化也就是观察者活动状态发生改变时才会往下走,否则直接结束该方法,activity的可见性发生变化时,首先更新观察者活动状态,mActive的值为newActive,紧接着如果观察者的活动状态是由不活动转化为活动时,则先将LiveData的处于活动状态的观察者个数加1,如果该观察者是唯一一个处于活动状态的观察者,则调用LiveData的onActive方法;如果观察者的活动状态是由活动转化为不活动时,则先将LiveData的处于活动状态的观察者个数减1,如果该观察者是最后一个从活动状态转化为不活动状态的观察者时,也就是说LiveData中不存在活动状态的观察者时,则调用LiveData的onInactive方法;这两个方法都是空方法,可以由开发人员自己继承去做一些操作。最后,如果是由不活动状态转化为活动状态,则会调用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;
}
这个方法是LiveData用来向观察者分发数据的方法。这里有两个boolean类型的标志变量,mDispatchingValue和mDispatchInvalidated,mDispatchingValue的值表示当前LiveData是否正在分发数据,mDispatchInvalidated可以设为true来表示当前正在执行的分发操作无效,如果当前正在执行分发操作,则将当前正在执行的分发操作置为无效,然后直接退出该方法,否则就进行分发操作,将mDispatchingValue设为 true表示当前正在执行分发,然后就执行do while循环,在循环里面执行分发操作,每次循环以后都会判断当前分发如果无效再执行一次循环分发数据,直到成功为止,首先会将分发操作置为有效,然后会判断该方法的参数是否为null,不为null则只向传入的观察者分发数据,否则就会循环遍历向所有的观察者分发数据,每次循环还会判断此次分发是否有效,因为也许分发过程中数据又发生了改变,那么就会退出遍历循环重新分发,分发给每个过程中调用的是considerNotify方法:
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
// Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
//
// we still first check observer.active to keep it as the entrance for events. So even if
// the observer moved to an active state, if we've not received that event, we better not
// notify for a more predictable notification order.
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
首先分发操作只对处于活动状态的观察者执行,如果观察者处于非活动状态,则直接退出该方法,接着会调用观察者的shouldBeActive方法:
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
顾名思义,该方法就是判断该观察者是否应该处于活动状态,为了防止观察者的活动状态没有及时更新,直接返回观察者观察的组件是否是可见的,如果观察者不应该处于活动状态,那么就调用观察者的activeStateChanged(false)更新状态后退出方法,否则就会判断版本号,这里解释一下版本号的作用:
LiveData有一个版本号,观察者也有一个最后版本号,每当LiveData的数据发生变化时,版本号都会+1,而每次更新观察者的数据时,都会将观察者的最后版本号的值置为LiveData的当前版本号,所以如果观察者的最后版本号的值为LiveData的当前版本号相等,则表示观察者拿到的数据是最新的。
所以这里就会判断观察者的最后版本号如果不小于LiveData的当前版本号,那么观察者的数据就是最新的,就不需要更新,直接退出方法,否则就将最后版本号的值值为LiveData的当前版本号,再更新数据,更新数据就是调用observer的onChanged方法。
再回到dispatchingValue方法,我们这里传入的观察者不为空,所以只需要更新该观察者的数据。
跳得有点远,再回到观察者的的onStateChanged,前面讲的是activity生命周期为destroyed时的流程,当不为destroyed时,则会先调用shouldBeActive()更新当前的活动状态,再调用activeStateChanged方法,而这个方法前面也已经讲过了,这里就不再赘述了。
到这里再总结一下,当组件生命周期发生变化时,首先判断是否为销毁状态,是的话就将观察者从LiveData和Lifecycle的观察者列表中删除。否则就会判断组件生命周期变化是否导致可见性发生了变化,是的话就更新观察者当前的活动状态,如果是从非活动状态转为活动状态,LiveData还需要向该观察者分发最新数据,观察者再根据版本号来决定是否需要更新。
LiveData更新数据时观察者是如何工作的
LiveData更新数据是从setValue方法开始的:
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
这个方法很简单,首先这个方法只能在主线程调用,接着会将版本号+1,然后更新数据,最后再将数据分发给所有观察者。
接着再看一下另一个更新数据的方法postValue:
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
这里首先会通过加锁判断是否有其他子线程在更新,因为子线程更新数据是先将数据赋值给mPendingData以后再拿着mPendingData更新的,更新以后又会将mPendingData设为NOT_SET(其实不是这样的,先这样说比较好理解,后面会分析),所以如果mPendingData为NOT_SET,则表示当前线程可以更新,然后将value赋值给mPendingData以后再执行更新操作,否则则表示当前有其他线程正在更新,那么就把value赋值给mPendingData,让这个正在更新的线程来帮自己更新,自己直接退出就行了,我们现在看一下是如何更新的:
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
public static ArchTaskExecutor getInstance() {
if (sInstance != null) {
return sInstance;
}
synchronized (ArchTaskExecutor.class) {
if (sInstance == null) {
sInstance = new ArchTaskExecutor();
}
}
return sInstance;
}
很容易看出是一个单例模式,返回一个ArchTaskExecutor对象,看一下它的相关成员变量和构造函数:
private TaskExecutor mDelegate;
@NonNull
private TaskExecutor mDefaultTaskExecutor;
private ArchTaskExecutor() {
mDefaultTaskExecutor = new DefaultTaskExecutor();
mDelegate = mDefaultTaskExecutor;
}
这里可知mDelegate = mDefaultTaskExecutor = new DefaultTaskExecutor();
接下来看一下它的postToMainThread函数:
@Override
public void postToMainThread(Runnable runnable) {
mDelegate.postToMainThread(runnable);
}
可以看出这是一个静态代理模式,代理给mDelegate执行了,而mDelegate又是DefaultTaskExecutor类的实例,进入DefaultTaskExecutor的postToMainThread方法:
@Override
public void postToMainThread(Runnable runnable) {
if (mMainHandler == null) {
synchronized (mLock) {
if (mMainHandler == null) {
mMainHandler = createAsync(Looper.getMainLooper());
}
}
}
//noinspection ConstantConditions
mMainHandler.post(runnable);
}
这里会通过DLC获取一个Handler对象mMainHandler:
private static Handler createAsync(@NonNull Looper looper) {
if (Build.VERSION.SDK_INT >= 28) {
return Handler.createAsync(looper);
}
if (Build.VERSION.SDK_INT >= 16) {
try {
return Handler.class.getDeclaredConstructor(Looper.class, Handler.Callback.class,
boolean.class)
.newInstance(looper, null, true);
} catch (IllegalAccessException ignored) {
} catch (InstantiationException ignored) {
} catch (NoSuchMethodException ignored) {
} catch (InvocationTargetException e) {
return new Handler(looper);
}
}
return new Handler(looper);
}
其实就是一个主线程的Handler,然后再在主线程执行runnable,这个runnable就是postToMainThread传入的mPostValueRunnable:
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
最后还是调用了setValue方法更新数据,这里要解释一下为什么之前说更新以后又会将mPendingData设为NOT_SET的说法不对,看完上面这个代码就明白了,他这里是将mPendingData设为NOT_SET以后才更新数据的,之前说如果当前线程试图更新数据时发现有另外一个线程正在更新数据,那么就会将值交给mPendingData以后就交给另一个线程不管了,它判断是否有另一个线程在更新数据的依据是mPendingData是否不为NOT_SET,意思就是说如果mPendingData不为NOT_SET那么另一个线程的更新的值是可以改变的,如果为NOT_SET,那么表示此时没有更新操作,或者更新操作的值已经无法改变了,那么就要自己亲自执行更新操作了,从代码中就能看出来,当将mPendingData的值赋给newValue以后,再怎么改变mPendingData的值也无法改变此次更新的结果了。
这就是LiveData的工作原理,个人感觉相对于Lifecycle要更好理解。
如果有什么不正确的地方欢迎指正!