Android Architecture Component之LiveData 分析

一 什么是LiveData

LiveData是一個(gè)可觀察數(shù)據(jù)變化的類,但是與其他觀察類不同的是,LiveData是可以感知到所持有類的生命周期的。所以我們一般用它來和Activity、Fragment或者service一起使用。這里有個(gè)很有好處的地方就是,LiveData的onChange方法,只會(huì)在activity在前臺(tái)的時(shí)候產(chǎn)生回調(diào),后面我們可以用例子來說明。

二 LiveData的好處

那么使用LiveData有什么好處呢?從LiveData的相關(guān)特性,我們可以歸納出以下幾點(diǎn):

1 確保UI和數(shù)據(jù)狀態(tài)保持一致
LiveData遵循觀察者模式,當(dāng)生命周期發(fā)生改變的時(shí)候,LiveData會(huì)通知觀察者對(duì)象。因此我們可以通過統(tǒng)一在觀察者對(duì)象數(shù)據(jù)中更新UI,而不是通過app數(shù)據(jù)的變更去改變UI。在我們這些對(duì)象發(fā)生變更的時(shí)候,我們的UI也會(huì)跟著改變。

2 不會(huì)有內(nèi)存泄漏
所有的觀察者都是綁定到owner的生命周期內(nèi)的,也就是說,如果owner被finish的時(shí)候,所有的觀察者也會(huì)被自動(dòng)銷毀。炒雞智能方便有木有?

3 不會(huì)因?yàn)锳ctivity被銷毀而導(dǎo)致崩潰
這種情況多數(shù)發(fā)生在我們的異步回調(diào)函數(shù)中,比如有時(shí)候我們回去通過異步線程來獲取網(wǎng)絡(luò)數(shù)據(jù)后,刷新我們的界面。這個(gè)時(shí)候,當(dāng)我們的activity被銷毀的時(shí)候,我們的異步線程回調(diào)才剛回來,這就導(dǎo)致了我們?cè)谝粋€(gè)廢棄的activity中更新他的UI,這就會(huì)導(dǎo)致異常崩潰的發(fā)生。

4 不再需要手動(dòng)去控制生命周期
UI組件只會(huì)在對(duì)象不是stop或者resume的時(shí)候進(jìn)行觀察,LiveData會(huì)自動(dòng)管理這一切。在正確的時(shí)候,給與觀察者以回調(diào)。

5 永遠(yuǎn)保持最新的數(shù)據(jù)狀態(tài)
當(dāng)觀察的對(duì)象不是處于激活狀態(tài)的時(shí)候,LiveData并不會(huì)去刷新數(shù)據(jù),而當(dāng)觀察的對(duì)象重新激活的時(shí)候,那么LiveData將會(huì)刷新最新的數(shù)據(jù)。最典型的是,如果你的Activity是后臺(tái)的時(shí)候,再次期間所有的數(shù)據(jù)變更,liveData都會(huì)選擇性的忽略,等到你重新喚醒Activity的時(shí)候,LiveData馬上就會(huì)刷新他的值,讓他和最后一個(gè)setValue(value)保持一致。

三 開始源碼之旅

接下來,我們從一段簡(jiǎn)單的源碼開始

viewModel.loadFiveUsers().observe(MainActivity.this, new Observer<List<User>>() {
        @Override
        public void onChanged(@Nullable List<User> users) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < users.size(); i++) {
                User user = users.get(i);
                sb.append("====================\n");
                sb.append("uid:" + user.getUid() + "\n " + user.getUserName() + "\n" + user.getLastName() + "\n");
                sb.append("\n");
            }
            tv_values.setText(sb.toString());
        }
    });

我們這里暫且忽略viewModel部門,我們只需要知道,viewModel.loadFiveUsers()返回的是一個(gè)LiveData<T>類型的數(shù)據(jù)就可以了。簡(jiǎn)單的說一下這段代碼,就是實(shí)時(shí)獲取當(dāng)前數(shù)據(jù)庫中的前5條數(shù)據(jù),并且把這5條數(shù)據(jù)通過TextView顯示出來。業(yè)務(wù)場(chǎng)景其實(shí)非常的簡(jiǎn)單。好了,接下來開始拆輪子

第一步:LiveData.observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer)Owner和observe是如何建立聯(lián)系的
我們進(jìn)入源碼的世界

 @MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
    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);
}

首先,LiveData強(qiáng)調(diào)的是,observe方法必須是在UI線程中進(jìn)行調(diào)用的。我們從源碼可知
1 如果當(dāng)前的owner是Destroyed狀態(tài)的,那么我們就直接忽略掉了,這個(gè)是顯而易見的。
2 LiveData會(huì)先將當(dāng)前的owner和observe結(jié)合在一起,生成一個(gè)wrapper對(duì)象,然后嘗試observe和wrapper當(dāng)成key和value 添加進(jìn)mObservers中,這個(gè)mObservers其實(shí)就是一個(gè)map對(duì)象。如果發(fā)現(xiàn)這個(gè)key對(duì)應(yīng)的value已經(jīng)有值了,并且這value并不是我們即將put進(jìn)去的value,那么就會(huì)拋錯(cuò)
3 加入不存在的話,那么wrapper將會(huì)被添加進(jìn)當(dāng)前owner的生命周期中,進(jìn)行監(jiān)聽。

第二步:setValue(T value)
LiveData提供了兩個(gè)setValue的方法,一個(gè)是同步情況的調(diào)用

@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}  

另一個(gè)是異步情況的調(diào)用

protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
   postTask = mPendingData == NOT_SET;
    mPendingData = value;
   }
   if (!postTask) {
       return;
   }
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}  

其實(shí)最后都是調(diào)用了 setValue((T) newValue);方法。我們來研究下這個(gè)方法,可以看到,他會(huì)先判斷當(dāng)前是否在主線程調(diào)用,如果不是的話,那么就會(huì)拋出錯(cuò)誤。然后就會(huì)把當(dāng)前LiveData的版本號(hào)mVersion++,把mData設(shè)置成最新的value。其實(shí)整個(gè)過程最麻煩的是dispatchingValue(null)這個(gè)方法。我們進(jìn)入這個(gè)方法進(jìn)行查看

private 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<T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

其實(shí)我們可以看到,這個(gè)個(gè)方法就是現(xiàn)在已有的觀察者進(jìn)行循環(huán),檢查到如果是當(dāng)前的觀察者,那么就調(diào)用considerNotify(iterator.next().getValue())方法。也即是找到最新的mData,進(jìn)行onchanged(mData)回調(diào)給觀察者。

 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);
}

其實(shí)這個(gè)方法,會(huì)調(diào)用到

 @Override
  boolean shouldBeActive() {
      return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
  }

這個(gè)方法就是會(huì)去判斷當(dāng)前的owner的狀態(tài)是否是active狀態(tài),進(jìn)行是否分發(fā)的動(dòng)作。

四 生命周期中LiveData的回調(diào)情況

1 關(guān)于:永遠(yuǎn)保持最新的數(shù)據(jù)狀態(tài)

我們主動(dòng)setValue(T value)方法后,liveData調(diào)用的onChanged(T value)流程已經(jīng)分析完畢了,那么前面我們所說的,當(dāng)觀察的對(duì)象不是處于激活狀態(tài)的時(shí)候,LiveData并不會(huì)去刷新數(shù)據(jù),而當(dāng)觀察的對(duì)象重新激活的時(shí)候,那么LiveData將會(huì)刷新最新的數(shù)據(jù)。最典型的是,如果你的Activity是后臺(tái)的時(shí)候,再次期間所有的數(shù)據(jù)變更,liveData都會(huì)選擇性的忽略,等到你重新喚醒Activity的時(shí)候,LiveData馬上就會(huì)刷新他的值,讓他和最后一個(gè)setValue(value)保持一致。這個(gè)是怎么實(shí)現(xiàn)的呢?

LifecycleBoundObserver 生命周期回調(diào)

其實(shí)就是如上圖所說的,我們的activity在后臺(tái)或者重新回到前臺(tái)的時(shí)候,都會(huì)回調(diào)到上面的onStateChanged()方法。當(dāng)Activity是后臺(tái)的時(shí)候,shouldBeActive返回的是false,那么

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);
        }
    }

中的dispatchingValue(this)就不會(huì)進(jìn)行分發(fā),從而不會(huì)觸發(fā)observe的onchanged(T mData) 方法。

2 Activity finish的時(shí)候,移除監(jiān)聽

上面的圖中我們可以看到,LiveData還會(huì)去判斷當(dāng)前的owner是否已經(jīng)被銷毀了,如果被銷毀了,還會(huì)調(diào)用removeObserver(mObserver);方法,這也就是我們不需要去關(guān)心內(nèi)存泄漏,或者在Activity finish情況下,還去嘗試更新UI的問題。

自此,LiveData的完整分析已經(jīng)完成。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容