距离上一次更新博客已经过去很久了,其实中间也有写一些东西但是没有认真发布到博客上,希望能坚持初心,把博客当作学习记录来激励自己持续学习。
- 当 LiveData 更新 value 的时候实际发生了什么?
- LiveData 是如何绑定观察者的生命周期的?
- 当我们订阅 LiveData 时,为什么只有当前观察者收到数据?
也许在使用 LiveData 时还有其他的问题,而所有问题的答案几乎都清楚的写在源码里。本篇文章中阅读的为androidx.lifecyle:lifecycle-livedata-core:2.2.0
中的 LiveData
一、构造 LiveData
构造 LiveData 有两种方式,一种使用默认构造函数,另一种可以在构造时初始化value的值。构造函数的内容很简单,初始化了mData
和 mVersion
,我们这里先记住这个 mVersion
public LiveData() { mData = NOT_SET; mVersion = START_VERSION; } public LiveData(T value) { mData = value; mVersion = START_VERSION + 1; } static final int START_VERSION = -1;
|
二、订阅 LiveData
订阅通常也有两种方式,一种是observe
传入 LifecycleOwner
另一种是observerForever
。 先从 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); }
|
上面的代码逻辑很简单,里面出现了几个我们可能关心的类或变量:mObservers
, LifecycleBoundObserver
。
其中 mObservers
是 SafeIterableMap
, 实际是个链表假装的 Map,这里不展开。key 是 observer,也就是上面方法中传进来的第二个参数,value 是ObserverWrapper
。
另一个 LifecycleBoundObserver
就比较关键了,从上面的信息可以推出它是ObserverWrapper
的一个子类。我们先从 owner.getLifecycle().addObserver(wrapper);
这个代码作为入口来看:
void dispatchEvent(LifecycleOwner owner, Event event) { mLifecycleObserver.onStateChanged(owner, event); mState = newState; }
|
既然 addObserver
可以把 wrapper
作为参数传入,那就说明它实现了 LifecycleEventObserver
接口,这里就解释了开头的第二个问题,让我们进入到LifecycleBoundObserver
类中:
public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { if (mOwner.getLifecycle().getCurrentState() == DESTROYED) { removeObserver(mObserver); return; } activeStateChanged(shouldBeActive()); }
|
先看shouldBeActive()
boolean shouldBeActive() { return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED); }
|
再来看activeStateChanged()
, 这个方法在抽象类 ObserverWrapper
中
void activeStateChanged(boolean newActive) { if (newActive == mActive) { return; } 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); } }
|
上面的代码我们可以知道一个 LiveData 很关键的点,当回调 onInactive
或者 Livedata 的 mActiveCount
为 0 的时候,并不是说 LiveData 没有观察者,而是它所有的观察者当前都处于未激活状态,这里千万不要搞混淆了。
另外可以看到这里可能会触发一次value
的分发,这里就解释了开篇第三个问题的一半,当我们第一次订阅LiveData的时候,会去绑定生命周期,然后会回调到 onStateChanged,当处于active后就会触发一次value的分发
三、当 setValue的时候发生了什么
第二个部分我们已经可以得出分发value
是通过dispatchingValue();
方法来实现的,那setValue
和postValue
应该最终都会调用这个函数,我们先看 setValue
@MainThread protected void setValue(T value) { assertMainThread("setValue"); mVersion++; mData = value; dispatchingValue(null); }
|
上面的代码很简单,所以核心在 dispatchingValue(null);
中,大家细心一点可以发现这里传入的参数为null
,而上面ObserverWrapper
传入的参数为 this
:
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; }
|
上面的代码主要有三个点
- 当传入了 wrapper 就会只通知这个观察者,也就解释了开头第三个问题
- 这个分发考虑一个多次分发value的问题,而处理的方式是停止前一次的分发,立即进入下一次的分发。比如第一次分发开始,紧接着更新了value,调用
dispatchingValue
,这时候会发现当前正在分发,于是将mDispatchInvalidated
标记为 true, 第一次分发在for循环中发现本次分发失效了,跳出for循环,然后while循环判断通过将再一次执行do中的代码,这时候会将mDispatchInvalidated
标记为false,顺利的走完for循环中的逻辑,跳出while循环,最后标记分发完成。
- 无论是通知一个还是通知全部,都进入到了
considerNotify(wrapper)
; 这个函数中
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); }
|
上面的代码就解释了开头的第一个问题
四、扩展问题
postValue 是如何实现的?
从源码可以看出来,当多次调用postValue时,如果主线程还没来得及处理前面的更新,则只会更新最后一次的value,并不会 post 多次runable到主线程去执行
protected void postValue(T value) { boolean postTask; synchronized (mDataLock) { postTask = mPendingData == NOT_SET; mPendingData = value; } if (!postTask) { return; } ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); } private final Runnable mPostValueRunnable = new Runnable() { public void run() { Object newValue; synchronized (mDataLock) { newValue = mPendingData; mPendingData = NOT_SET; } setValue((T) newValue); } };
|
MutableLiveData 和 LiveData 的区别
这个甚至不用看源码,熟悉kotlin就知道跟 List 和 MutableList 的区别一样。LiveData 中 setValue
和 postValue
都是 protected
, 而MutableLiveData 把它们变成了 public
。
推荐 MutableLiveData 只提供给有修改data权限的类使用,对于一些只取值的类(UI等)则提供 LiveData,避免被错误修改。
如果之前对 RxJava 比较熟悉的同学基本都能理解这两个方法的区别和原理。本质上和 RxJava 的 map 和 flatmap类似
public static <X, Y> LiveData<Y> map( @NonNull LiveData<X> source, @NonNull final Function<X, Y> mapFunction) { final MediatorLiveData<Y> result = new MediatorLiveData<>(); result.addSource(source, new Observer<X>() { @Override public void onChanged(@Nullable X x) { result.setValue(mapFunction.apply(x)); } }); return result; } public static <X, Y> LiveData<Y> switchMap( @NonNull LiveData<X> source, @NonNull final Function<X, LiveData<Y>> switchMapFunction) { final MediatorLiveData<Y> result = new MediatorLiveData<>(); result.addSource(source, new Observer<X>() { LiveData<Y> mSource; @Override public void onChanged(@Nullable X x) { LiveData<Y> newLiveData = switchMapFunction.apply(x); if (mSource == newLiveData) { return; } if (mSource != null) { result.removeSource(mSource); } mSource = newLiveData; if (mSource != null) { result.addSource(mSource, new Observer<Y>() { @Override public void onChanged(@Nullable Y y) { result.setValue(y); } }); } } }); return result; }
|
事实上我们完全可以自己去根据项目需求来自定义一些类似RxJava的操作符。
五、总结
没有总结,以后关于源码的文章都不写总结了。希望自己和看到这篇文章的人都能静下来认真看完源码学习的过程,然后得出自己的理解和总结,而不是看了两段就直接跳到后面来背总结。