源碼 livedata 2.0.0
Jetpack里L(fēng)iveData的相關(guān)類(lèi)不多斤彼,類(lèi)圖見(jiàn)下
[站外圖片上傳中...(image-ec369-1555299590976)]
Observer:作為interface,觀察者卒茬,數(shù)據(jù)發(fā)生改變,通過(guò)onChanged()響應(yīng)改變永品;
LiveData:抽象出來(lái)的統(tǒng)一被觀察者對(duì)象,與Observer建立觀察聯(lián)系的方法是observe()方法击纬。
ComputableLiveData:可計(jì)算的LiveData鼎姐,內(nèi)部持有LiveData,使原數(shù)據(jù)失效并出刷新數(shù)據(jù)更振。
MutableLiveData:這個(gè)方法只是將LiveData的方法權(quán)限修改炕桨,并未實(shí)現(xiàn)其他業(yè)務(wù)。
通常在使用的時(shí)候殃饿,LiveData有可能是由其他類(lèi)或庫(kù)創(chuàng)建出來(lái)的實(shí)例(如Room提供了toLiveData()方法)谋作,也可能是自己 new 出來(lái)的對(duì)象。訂閱見(jiàn)下
mLiveData.observe(Activity.this,Observer(){
Log.d(TAG, it.toString());
})
以正常一次數(shù)據(jù)更新來(lái)看其內(nèi)部實(shí)現(xiàn)乎芳,看數(shù)據(jù)改變的入口遵蚜;
異步更新:mLiveData.postValue(data);
同步更新:mLiveData.setValue(data);
同步setValue()
同步更新方法相對(duì)簡(jiǎn)單,先看看它怎么實(shí)現(xiàn)的奈惑。setValue()方法里首先對(duì)線程進(jìn)行判定吭净,它必須在主線程里面運(yùn)行,之后保存發(fā)更改的數(shù)據(jù)對(duì)象肴甸,并調(diào)用分發(fā)函數(shù)寂殉,dispatchingValue(null);
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;
}
內(nèi)部核心considerNotify(),由于這里傳入的是null原在,因此從 mObservers里面獲取數(shù)據(jù)友扰,而LiveData.mObservers對(duì)象則是在observe的時(shí)候添加了數(shù)據(jù)彤叉。
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;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
最后調(diào)用了onChanged(),完成響應(yīng)回調(diào)村怪。其中有檢測(cè)了觀察者是否是正在觀察等秽浇。同步的代碼流程就完成了。
異步postValue()
異步方法核心是線程切換甚负,懸掛數(shù)據(jù)處理柬焕。
因此,postValue()內(nèi)部必須先對(duì)數(shù)據(jù)進(jìn)行加鎖梭域,判定是不是可以發(fā)送的數(shù)據(jù)斑举。代碼也給了說(shuō)明備注,若在主線程Runnable數(shù)據(jù)時(shí)再連續(xù)postValue()多個(gè)數(shù)據(jù)病涨,最后一個(gè)數(shù)據(jù)才會(huì)被發(fā)送出去富玷。見(jiàn)下,會(huì)直接reutrn .
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
在主線程上將懸掛數(shù)據(jù)發(fā)送出去没宾。看看它是怎么確定在主線程的?
postToMainThread()是虛方法凌彬, ArchTaskExecutor.getInstance()得到的實(shí)例mDefaultTaskExecutor,即DefaultTaskExecutor類(lèi)循衰,它的postToMainThread()如下:
public void postToMainThread(Runnable runnable) {
if (mMainHandler == null) {
synchronized (mLock) {
if (mMainHandler == null) {
mMainHandler = new Handler(Looper.getMainLooper());
}
}
}
//noinspection ConstantConditions
mMainHandler.post(runnable);
}
獲取到主線程的Looper铲敛,創(chuàng)建Handdler,并post会钝,因此會(huì)在主線程發(fā)送伐蒋。
再看mPostValueRunnable內(nèi)部是怎么處理的?
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
setValue((T) newValue);
}
};
調(diào)用setValue()迁酸,這里已經(jīng)在主線程上了先鱼,因此它是一個(gè)同步發(fā)送事件了,之后的流程就是前面分析的流程奸鬓。
至此焙畔,LiveData的核心代碼就分析完成了。
再看一看具有計(jì)算功能的LiveData串远;
可計(jì)算LiveData (ComputableLiveData)
從功能上來(lái)說(shuō)宏多,使原數(shù)據(jù)失效并出刷新數(shù)據(jù)。
內(nèi)部實(shí)現(xiàn)核心:mRefreshRunnable澡罚、mInvalidationRunnable
先看刷新mInvalidationRunnable
final Runnable mInvalidationRunnable = new Runnable() {
@MainThread
@Override
public void run() {
boolean isActive = mLiveData.hasActiveObservers();
if (mInvalid.compareAndSet(false, true)) {
if (isActive) {
mExecutor.execute(mRefreshRunnable);
}
}
}
};
顯而易見(jiàn)的伸但,它去執(zhí)行的還是mRefreshRunnable,只是將mInvalid標(biāo)志為true, 那看看絕對(duì)核心mRefreshRunnable留搔,
@VisibleForTesting
final Runnable mRefreshRunnable = new Runnable() {
@WorkerThread
@Override
public void run() {
boolean computed;
do {
computed = false;
// compute can happen only in 1 thread but no reason to lock others.
if (mComputing.compareAndSet(false, true)) {
// as long as it is invalid, keep computing.
try {
T value = null;
while (mInvalid.compareAndSet(true, false)) {
computed = true;
value = compute();
}
if (computed) {
mLiveData.postValue(value);
}
} finally {
// release compute lock
mComputing.set(false);
}
}
// check invalid after releasing compute lock to avoid the following scenario.
// Thread A runs compute()
// Thread A checks invalid, it is false
// Main thread sets invalid to true
// Thread B runs, fails to acquire compute lock and skips
// Thread A releases compute lock
// We've left invalid in set state. The check below recovers.
} while (computed && mInvalid.get());
}
};
其邏輯線更胖,如果使用失效,需要調(diào)用compute()去重新計(jì)算新的數(shù)據(jù)源回來(lái),并且在這種情況下會(huì)調(diào)用LiveData的異步更新却妨。
原數(shù)據(jù)失效對(duì)外的方法是invalidate()饵逐。它內(nèi)部將mInvalidationRunnable對(duì)象post到主線程里面。