上一篇讲了LiveData的基本使用和postValue丢失信息的问题,接下来就从源码角度看看LiveData是如何工作的。
简单模式的工作原理
之所以称setValue方法发送消息的模式称之为简单模式,因为他是工作在主线程中,不涉及线程切换,也不涉及信息丢弃逻辑。上代码
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
这里代码比较简单,设置了一下版本号,将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,并调用considerNotify方法。至于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;
observer.mObserver.onChanged((T) mData);
}
最后一行,调用了observer的onChanged方法,整个流程算是完成了。
这里还有两个问题observer怎么来的,还有就是considerNotify方法中会校验observer的状态。一个一个来看。
- observer的注册过程
@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);
}
添加观察者的方式比较简单 mObservers.putIfAbsent(observer, wrapper);这里还很友好的做了判重的操作。而且该方法只能在主线程中调用,因此不会因为重复添加观察者而造成发送的消息重复
- observer的生命周期感知能力
还是上面代码,添加观察者的时候,传递了一个参数为LifecycleOwner,方法最后调用了
owner.getLifecycle().addObserver(wrapper);
看到这里,基本上算是明白了,核心就在于Lifecycle,思路还是很清晰的。看看它是如何实现的,源码中提供了一个LifeCycle的实现类LifecycleRegistry,而我们的Fragment和Activity都会持有LifecycleRegistry这个对象
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
每当生命周期发生变化时,fragment或者activity都会通过handleLifecycleEvent方法将消息发送给LifecycleRegistry
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
enforceMainThreadIfNeeded("handleLifecycleEvent");
moveToState(event.getTargetState());
}
private void moveToState(State next) {
if (mState == next) {
return;
}
mState = next;
if (mHandlingEvent || mAddingObserverCounter != 0) {
mNewEventOccurred = true;
// we will figure out what to do on upper level.
return;
}
mHandlingEvent = true;
sync();
mHandlingEvent = false;
}
生命周期感知能力到这就圆满结束了。
接下来看看稍微复杂一点的模式
postValue方式,其实看完setValue方式,这个方式就简单多了
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
先看消息遗弃策略,这里大部分代码都是丢弃消息的逻辑,简单来讲,就是如果还有旧消息没来得及发送的时候来了新消息,则丢弃旧消息。看起来虽然有点迷惑性,异步执行的时候,mPendingData保留的是最新的value,而这个变量保存的才是带发送的消息。由于消息对象使用的是一个变量存储而非集合,因此,消息过载时,定然会有放弃策略。至于为什么如此设计,我也搞不清楚,有人知道的话,辛苦留言告知一下。
postValue这个方法设计初衷就是在子线程中执行,因此需要通过线程转化的方式将消息退入主线程中。ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);这行代码就是线程切换的关键。
这里的runnable比较简单
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方法,而这里的value就是上一步保存的全局变量mPendingData。
而postToMainThread最终调用的为DefaultTaskExecutor中的postToMainThread方法
public void postToMainThread(Runnable runnable) {
if (mMainHandler == null) {
synchronized (mLock) {
if (mMainHandler == null) {
mMainHandler = createAsync(Looper.getMainLooper());
}
}
}
//noinspection ConstantConditions
mMainHandler.post(runnable);
}
通过handler发送一个接口,handler会直接执行Runnable的run方法。也就是说这个方法还是执行在主线程中的。
完美结束,可以看出,LiveData的设计还是比较简单的
网友评论