Android架構(gòu)組件(Architecture Components)之 LiveData詳解

寫在前面

在上一篇文章Android架構(gòu)組件(Architecture Components)之 Lifecycle詳解中诅挑,說到了要想了解LiveData夫嗓,需要先了解Lifecycle。所以這次就開始來講講LiveData了篙挽。希望還沒看過的朋友先看下上一篇文章荆萤,因?yàn)檫@篇文章會(huì)有一些依賴到上一篇文章的。

LiveData

結(jié)構(gòu)

先來看看LiveData的結(jié)構(gòu):


livedata.png

LiveData其實(shí)是一個(gè)抽象類铣卡,但它的內(nèi)部并沒有抽象的方法链韭。我們可以通過MutableLiveData來使用它。它的實(shí)現(xiàn)僅僅只是將setValue()postValue()方法設(shè)置為public煮落。所以重點(diǎn)還是應(yīng)該來分析LiveData敞峭。除此之外,LiveData還有幾個(gè)內(nèi)部類:

observer.png

和LifecycleRegistry一樣蝉仇,LiveData內(nèi)部也維護(hù)著一個(gè)觀察者列表:mObservers旋讹,它的類型是SafeIterableMap<Observer<? super T>, ObserverWrapper>,對(duì)應(yīng)存儲(chǔ)的值是ObserverWrapper轿衔,用了裝飾器模式將Observer給包裝起來沉迹。為什么要將Observer包裝起來呢?這是因?yàn)長(zhǎng)iveData允許我們有兩種不同的觀察模式:有生命周期限制的觀察者和一直觀察的觀察者害驹,分別對(duì)應(yīng)著它的兩個(gè)子類:LifecycleBoundObserver和AlwaysActiveObserver鞭呕。兩種不同的方式供我們選擇,給我們帶來了很高的靈活性宛官。

observe()

回到LiveData的方法上葫松,先從使用頻率最高的observe()方法入手。

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

首先要確保該方法是在主線程上調(diào)用的摘刑,否則會(huì)直接拋出異常进宝。接著判斷如果依附的LifecycleOwner目前已經(jīng)是DESTROYED狀態(tài)的話,就直接返回了枷恕。緊接著將方法傳入的Observer和LifecycleOwner封裝成一個(gè)LifecycleBoundObserver添加到隊(duì)列中党晋。最后向LifecycleOwner中注冊(cè)了一個(gè)觀察者。到這里為止,有了觀察者和被觀察者未玻,整套機(jī)制就能運(yùn)轉(zhuǎn)起來了灾而。

上一篇文章的最后,講到了dispatchEvent()方法就結(jié)束了扳剿,再來回顧一下:

void dispatchEvent(LifecycleOwner owner, Event event) {
    State newState = getStateAfter(event);
    mState = min(mState, newState);
    mLifecycleObserver.onStateChanged(owner, event);
    mState = newState;
}

當(dāng)時(shí)說了:

LifecycleObserver是一個(gè)LifecycleEventObserver旁趟,也是一個(gè)接口來著,繼承了LifecycleObserver

結(jié)合上面的類圖庇绽,LifecycleBoundObserver不僅是繼承了ObserverWrapper锡搜,它還實(shí)現(xiàn)了LifecycleEventObserver接口。所以當(dāng)LifecycleOwner的狀態(tài)發(fā)生變化時(shí)瞧掺,會(huì)走到LifecycleBoundObserver的onStateChanged()方法中:

@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
    if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
        removeObserver(mObserver);
        return;
    }
    activeStateChanged(shouldBeActive());
}

如果生命周期的狀態(tài)變成了DESTROYED,LiveData會(huì)自動(dòng)幫我們移除掉觀察者耕餐,避免內(nèi)存泄漏。

shouldBeActive()是一個(gè)抽象方法辟狈,來看下它的兩個(gè)子類的不同肠缔。

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

// AlwaysActiveObserver
@Override
boolean shouldBeActive() {
    return true;
}

LifecycleBoundObserver中,只有當(dāng)前的狀態(tài)至少處于STARTED的才會(huì)被認(rèn)為是活躍的哼转。而AlwaysActiveObserver由于沒有生命周期的概念明未,所以一直是處于活躍的狀態(tài)的。這是它們的區(qū)別所在壹蔓。

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

這里主要是判斷Observer是否應(yīng)該處于活躍狀態(tài)趟妥,如果是的話,才去更新數(shù)據(jù)佣蓉。這里又看到了熟悉的dispatchXXX()方法煮纵。

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

重點(diǎn)在considerNotify()方法上:

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

在這里會(huì)最后一次去檢查Observer是否處于激活狀態(tài),并且目前的新的數(shù)據(jù)版本是否比當(dāng)前高偏螺,條件都滿足的話就會(huì)通知Observer更新數(shù)據(jù)了行疏。

observeForever()

除了observe()方法外,還有一個(gè)observeForever()方法套像。這個(gè)比較簡(jiǎn)單酿联,就是普通的觀察者模式。使用這個(gè)方法夺巩,一定要注意贞让,要在恰當(dāng)?shù)臅r(shí)機(jī),通過removeObserver()或者removeObservers()將觀察者移除掉柳譬,否則很可能會(huì)發(fā)生內(nèi)存泄漏喳张。

setValue()

通過LifecycleOwner的生命周期變化來決定是否要通知觀察者,這只是LiveData通知觀察者的一種方式美澳。當(dāng)數(shù)據(jù)發(fā)生變化時(shí)销部,LiveData也會(huì)通知觀察者摸航。

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

當(dāng)數(shù)據(jù)發(fā)生變化時(shí),會(huì)更新版本號(hào)舅桩,然后又是調(diào)用了dispatchingValue(),流程還是和上面的一樣酱虎,就不再講下去了。

postValue()

上面的setValue()要求在主線程中調(diào)用擂涛,如果是在子線程想更新數(shù)據(jù)的話读串,可以使用這個(gè)方法。

寫在最后

和上一篇的LifecycleOwner結(jié)合起來撒妈,總算是把這套加入生命周期的觀察者模式給理清了恢暖。剩下的就差ViewModel還沒有分析了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末狰右,一起剝皮案震驚了整個(gè)濱河市胀茵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌挟阻,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,464評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件峭弟,死亡現(xiàn)場(chǎng)離奇詭異附鸽,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)瞒瘸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門坷备,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人情臭,你說我怎么就攤上這事省撑。” “怎么了俯在?”我有些...
    開封第一講書人閱讀 169,078評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵竟秫,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我跷乐,道長(zhǎng)肥败,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,979評(píng)論 1 299
  • 正文 為了忘掉前任愕提,我火速辦了婚禮馒稍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘浅侨。我一直安慰自己纽谒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,001評(píng)論 6 398
  • 文/花漫 我一把揭開白布如输。 她就那樣靜靜地躺著鼓黔,像睡著了一般央勒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上请祖,一...
    開封第一講書人閱讀 52,584評(píng)論 1 312
  • 那天订歪,我揣著相機(jī)與錄音,去河邊找鬼肆捕。 笑死刷晋,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的慎陵。 我是一名探鬼主播眼虱,決...
    沈念sama閱讀 41,085評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼席纽!你這毒婦竟也來了捏悬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,023評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤润梯,失蹤者是張志新(化名)和其女友劉穎过牙,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體纺铭,經(jīng)...
    沈念sama閱讀 46,555評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡寇钉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,626評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了舶赔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扫倡。...
    茶點(diǎn)故事閱讀 40,769評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖竟纳,靈堂內(nèi)的尸體忽然破棺而出撵溃,到底是詐尸還是另有隱情,我是刑警寧澤锥累,帶...
    沈念sama閱讀 36,439評(píng)論 5 351
  • 正文 年R本政府宣布缘挑,位于F島的核電站,受9級(jí)特大地震影響桶略,放射性物質(zhì)發(fā)生泄漏卖哎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,115評(píng)論 3 335
  • 文/蒙蒙 一删性、第九天 我趴在偏房一處隱蔽的房頂上張望亏娜。 院中可真熱鬧,春花似錦蹬挺、人聲如沸维贺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽溯泣。三九已至虐秋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間垃沦,已是汗流浹背客给。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評(píng)論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留肢簿,地道東北人靶剑。 一個(gè)月前我還...
    沈念sama閱讀 49,191評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像池充,于是被迫代替她去往敵國和親桩引。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,781評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容