LiveData 源碼解析
之前做過一篇關(guān)于Lifecycle的源碼解析,里面分析了
- 生命周期擁有者如何進行生命周期的感知(通過Fragment)
- 當生命周期變化時,如何進行進行通知:將Obsever進行包裝,生成LifecycleEventObserver的具體實現(xiàn)來,然后在生命周期變化時,調(diào)用其對應的狀態(tài)的分發(fā)。
在通常進行使用的過程中,我們都是將數(shù)據(jù)通過 LiveData 進行一層包裝,然后就可以進行其數(shù)據(jù)的變化監(jiān)聽了,那么其具體是如何實現(xiàn)的呢?
慣例,先來個簡單的測試demo
object SplashViewModel{
var logined = MutableLiveData<Boolean>()
init {
logined.postValue(true)
}
}
class SplashActivity : BaseBindingActivity<ActivitySplashBinding, SplashViewModel>() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
SplashViewModel.logined.observe(this, Observer { print(it)})
}
}
只需要一個簡單的 observe() 方法,就可以實現(xiàn)生命周期的監(jiān)聽,然后將數(shù)據(jù)發(fā)送到我們的Activity中,我們看看這個方法里面到底做了什么
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)) {
//如果已經(jīng)存在,拋異常
throw new IllegalArgumentException("Cannot add the same observer with different lifecycles");
}
if (existing != null) {
return;
}
//增加一個監(jiān)聽者
owner.getLifecycle().addObserver(wrapper);
}
可以看到,只是將我們的生命周期擁有者和監(jiān)聽者進行了一次包裝,生成了 LifecycleBoundObserver 類,然后將它添加到監(jiān)聽者列表中。
在之前的Lifecycle的源碼解析文章中,我們了解到,當頁面發(fā)生變化時,會調(diào)用監(jiān)聽者的 onStateChanged() 方法。
@Override
boolean shouldBeActive() {//判斷當前頁面是否屬于激活狀態(tài)(即可見狀態(tài))
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
//如果頁面銷毀了,則直接移除當前對應的監(jiān)聽者
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
//進行狀態(tài)的變更
activeStateChanged(shouldBeActive());
}
所以當界面的生命周期變化時,會調(diào)用 activeStateChanged() 來進行狀態(tài)的變更處理
//進行狀態(tài)的轉(zhuǎn)變
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
//LiveData的激活的觀察者數(shù)量進行變化
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
//原來沒有激活的觀察者,現(xiàn)在有了新增的
// 說明LiveData從無激活的觀察者->有激活的觀察者
onActive();//留下鉤子,給繼承者使用
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
//當前頁面未激活,并且變化后,LiveData中處于激活狀態(tài)的觀察者數(shù)量為0,
// 說明LiveData從有激活的觀察者->無激活的觀察者
onInactive();//留下鉤子,給繼承者使用
}
if (mActive) {//如果頁面變化為了激活狀態(tài),那么進行數(shù)據(jù)的分發(fā)
dispatchingValue(this);
}
}
}
這里主要根據(jù)頁面的激活數(shù),預留了兩個鉤子函數(shù),用戶可以做一些自己的數(shù)據(jù)處理。最主要的還是 dispatchingValue() 中的數(shù)據(jù)處理。
//分發(fā)數(shù)據(jù)
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
//如果正在分發(fā),則將mDispatchInvalidated置為true,那么在分發(fā)過程中,會根據(jù)這個標志位重新新數(shù)據(jù)的分發(fā)
mDispatchInvalidated = true;
return;
}
//標記正在進行數(shù)據(jù)的分發(fā)
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {//如果有對應的監(jiān)聽者,直接分發(fā)給對應的監(jiān)聽者
considerNotify(initiator);
initiator = null;
} else {
//遍歷所有的觀察者,然后進行數(shù)據(jù)的分發(fā),
// 如果分發(fā)過程中,發(fā)現(xiàn)mDispatchInvalidated變化了,那么說明有新的數(shù)據(jù)變更,則退出當前混選,然后從新分發(fā)新的數(shù)據(jù)
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
//通知某個觀察者進行了數(shù)據(jù)的變化
private void considerNotify(ObserverWrapper observer) {
//觀察者未激活,返回
if (!observer.mActive) {
return;
}
//觀察者當前狀態(tài)為激活,但是當前變?yōu)榱瞬豢梢姞顟B(tài),那么調(diào)用
//activeStateChanged方法
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
//如果數(shù)據(jù)版本已經(jīng)是最新的了,那么直接返回
if (observer.mLastVersion >= mVersion) {
return;
}
//修改數(shù)據(jù)版本號
observer.mLastVersion = mVersion;
//調(diào)用監(jiān)聽者的onChanged方法
observer.mObserver.onChanged((T) mData);
}
在數(shù)據(jù)分發(fā)過程中,根據(jù)相應的觀察者數(shù)據(jù)版本號,然后和當前的數(shù)據(jù)的版本號進行比較,如果是新的數(shù)據(jù),那么調(diào)用觀察者的 onChange()方法,也就是我們在開始時寫的測試demo中的 print(it) 。
總結(jié)一下頁面發(fā)生變化時,數(shù)據(jù)的處理流程:
- 當頁面發(fā)生變化,從不可見變?yōu)榭梢姇r,會將LiveData中的數(shù)據(jù)版本號跟對應的觀察者中的版本號進行比較,如果大,則調(diào)用onChanged()進行數(shù)據(jù)的回調(diào)。
- 如果頁面為不可見,那么不會進行數(shù)據(jù)的回調(diào)處理。
那么當我們使用 setValue() ,或者 postValue() 時,LiveData 又是做了什么處理呢?
我們先看看 setValue()
protected void setValue(T value) {
assertMainThread("setValue");
//記錄當前數(shù)據(jù)的版本號
mVersion++;
//記錄設置的數(shù)據(jù)值
mData = value;
//進行數(shù)據(jù)的分發(fā)
dispatchingValue(null);
}
可以看到,直接將數(shù)據(jù)版本號+1,然后進行了數(shù)據(jù)的分發(fā),dispatchingValue() 我們剛才進行過分析,如果參數(shù)為null,那么會遍歷所有的監(jiān)聽者,逐個通知所有觀察者進行了數(shù)據(jù)的變化(前提是觀察者處于激活狀態(tài))。
我們再看看 postValue()
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
//通過線程池分發(fā)到主線程去處理
ArchTaskExecutor.getInstance().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);
}
};
可以看到, postValue() 通過線程池技術(shù),將數(shù)據(jù)在主線程進行了 setValue()。
匯總
1.當生命周期不可見時,會將最新的數(shù)據(jù)保存在LiveData中,然后保存相應的版本號,當其可見時,會將數(shù)據(jù)變化通知
2.當LiveData中的數(shù)據(jù)變化時,會遍歷所有的監(jiān)聽頁面,然后進行數(shù)據(jù)的變化通知。
附帶一張ObserverWrapper
的結(jié)構(gòu)圖
本文由博客一文多發(fā)平臺 OpenWrite 發(fā)布!