Android架構(gòu)組件之LiveData源碼解析

LiveData是Google發(fā)布的一個(gè)架構(gòu)組件,它是一個(gè)數(shù)據(jù)持有類(lèi)金矛,并且數(shù)據(jù)可以被觀察毙玻。區(qū)別于普通的被觀察者,LiveData最大的特點(diǎn)是具備生命周期感知能力速和,即它僅更新處于活動(dòng)生命周期狀態(tài)的應(yīng)用程序組件觀察者(例如Activity/Fragment)意蛀。因此耸别,LiveData可以很好的解決內(nèi)存泄漏問(wèn)題,以及常見(jiàn)的view空指針異常县钥。

一秀姐、LiveData如何感知生命周期

Android架構(gòu)組件之Lifecycle源碼解析一文中,我們了解到Lifecycle-Aware組件的核心就是生命周期感知若贮,要明白LiveData為什么能感知生命周期省有,就要以Lifecycle-Aware組件的原理為基礎(chǔ)。由于26.1.0及更高版本Support支持庫(kù)中的Activity和Fragment已經(jīng)實(shí)現(xiàn)了LifecycleOwner接口谴麦,因此Activity/Fragment就是LifecycleOwner蠢沿,而且它們內(nèi)部都會(huì)有一個(gè)LifecycleRegistry來(lái)存放生命周期State、Event等匾效。通過(guò)Lifecycle-Aware源碼分析舷蟀,我們可以知道在初始化Lifecycle組件時(shí)會(huì)為每個(gè)Activity/Fragment添加一個(gè)ReportFragment(無(wú)UI界面的Fragment),當(dāng)Activity執(zhí)行相應(yīng)生命周期方法的時(shí)候面哼,也會(huì)同步的執(zhí)行ReportFragment的生命周期方法野宜。因此,Lifecycle組件的核心就是通過(guò)無(wú)UI界面的Fragment來(lái)實(shí)現(xiàn)生命周期的監(jiān)聽(tīng)魔策,它會(huì)在執(zhí)行其生命周期方法的時(shí)候更新LifecycleRegistry里的生命周期State匈子、Event,,并且通過(guò)handleLifecycleEvent()方法來(lái)通知對(duì)應(yīng)的觀察者闯袒。

基于Lifecycle組件生命周期感知原理虎敦,那么只要讓LiveData注冊(cè)對(duì)Activity/Fragment的生命周期的監(jiān)聽(tīng),那么LiveData自然也就擁有了生命周期感知能力政敢。具體看一下LiveData的源碼實(shí)現(xiàn):

    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        ... ...
        owner.getLifecycle().addObserver(wrapper);
    }

由源碼可知其徙,如果當(dāng)前的LifecycleOwner處于DESTROYED狀態(tài),則忽略喷户。否則唾那,將傳入的觀察者做一個(gè)封裝,然后添加到Activity/Fragment的LifecycleRegistry中去摩骨,當(dāng)Activity/Fragment的什么周期發(fā)生變化時(shí)通贞,就會(huì)通知這個(gè)封裝的觀察者,即LiveData擁有了生命周期感知能力恼五。

二昌罩、LiveData注冊(cè)觀察者

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

由源碼可知,observe()注冊(cè)觀察者方法運(yùn)行在主線程灾馒。同時(shí)茎用,observe()方法會(huì)將傳入的觀察者對(duì)象封裝成一個(gè)LifecycleBoundObserver對(duì)象,之后再將這個(gè)wrapper對(duì)象添加到Activity/Fragment的LifecycleRegistry中去。因此轨功,對(duì)于Activity/Fragment而言旭斥,這個(gè)wrapper對(duì)象是觀察者,Activity/Fragment生命周期的變化都會(huì)通知到wrapper古涧。

那么垂券,緊接著我們一起來(lái)看一下LifecycleBoundObserver的源碼,而且配合上LifecycleRegistry靜態(tài)內(nèi)部類(lèi)ObserverWithState的源碼看效果更佳:

    // LifecycleRegistry # ObserverWithState
    static class ObserverWithState {
        State mState;
        GenericLifecycleObserver mLifecycleObserver;

        ObserverWithState(LifecycleObserver observer, State initialState) {
            mLifecycleObserver = Lifecycling.getCallback(observer);
            mState = initialState;
        }

        void dispatchEvent(LifecycleOwner owner, Event event) {
            State newState = getStateAfter(event);
            mState = min(mState, newState);
            mLifecycleObserver.onStateChanged(owner, event);
            mState = newState;
        }
    }
    // LiveData # LifecycleBoundObserver
    class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
        @NonNull final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {
            super(observer);
            mOwner = owner;
        }

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

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

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }

由源碼可知羡滑,當(dāng)Activity/Fragment生命周期發(fā)生變化時(shí)菇爪,最終會(huì)去回調(diào)觀察者的onStateChanged()方法。因此柒昏,我們先看一下LifecycleBoundObserver的onStateChanged()方法凳宙。很明顯,如果Activity/Fragment的當(dāng)前狀態(tài)是DESTROYED职祷,那么就將這個(gè)觀察者移除氏涩,也就意味著解除了與Activity/Fragment的關(guān)聯(lián),這就是LiveData可以避免內(nèi)存泄漏的原因有梆。接著是尖,會(huì)調(diào)用activeStateChanged()方法。

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

可以看到淳梦,當(dāng)LifecycleOwner的狀態(tài)處于STARTED或RESUMED時(shí)析砸,傳入newActive的值為true昔字,即LifecycleBoundObserver會(huì)被標(biāo)記為激活狀態(tài)爆袍,生命周期變化將會(huì)通知處于激活狀態(tài)的觀察者。

三作郭、LiveData通知觀察者

在上面的分析中陨囊,我們可以知道當(dāng)Activity/Fragment生命周期變化時(shí),如果Activity/Fragment處于活動(dòng)狀態(tài)夹攒,則會(huì)將生命周期變化通知觀察者蜘醋。
其次,我們也可以通過(guò)改變LiveData里面的數(shù)據(jù)內(nèi)容咏尝,然后再將數(shù)據(jù)的變化通知觀察者压语。具體主要體現(xiàn)在setValue()和postValue()這兩個(gè)方法上。

    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }
    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

由源碼可知编检,setValue()方法只能運(yùn)行在主線程上胎食,而postValue()方法可以運(yùn)行在任意線程上,但是Observer的OnChange回調(diào)最終會(huì)執(zhí)行在主線程上允懂。

我們注意到厕怜,不管是哪種通知觀察者的方式,都會(huì)調(diào)用到dispatchingValue()這個(gè)方法,下面就具體來(lái)看一下:

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

由源碼可知粥航,mDispatchingValue和mDispatchInvalidated只在dispatchingValue方法中使用琅捏,顯然這兩個(gè)變量是為了防止重復(fù)分發(fā)相同的內(nèi)容。接下來(lái)递雀,我們注意到柄延,無(wú)論傳入的initiator是否為空,都會(huì)走到considerNotify()這個(gè)方法:

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

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

由源碼可知缀程,如果Activity/Fragment處于非活動(dòng)狀態(tài)拦焚,則忽略。也就是說(shuō)杠输,如果當(dāng)前界面是不可見(jiàn)的赎败,那么就不會(huì)去通知觀察者,因此可以解決常見(jiàn)的view空指針異常問(wèn)題蠢甲。如果當(dāng)前界面處于活動(dòng)狀態(tài)僵刮,則會(huì)去回調(diào)注冊(cè)進(jìn)來(lái)的觀察者的onChanged()方法,之后進(jìn)行相應(yīng)的邏輯操作鹦牛。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末搞糕,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子曼追,更是在濱河造成了極大的恐慌窍仰,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件礼殊,死亡現(xiàn)場(chǎng)離奇詭異驹吮,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)晶伦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)碟狞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人婚陪,你說(shuō)我怎么就攤上這事族沃。” “怎么了泌参?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵脆淹,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我沽一,道長(zhǎng)盖溺,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任锯玛,我火速辦了婚禮咐柜,結(jié)果婚禮上兼蜈,老公的妹妹穿的比我還像新娘。我一直安慰自己拙友,他們只是感情好为狸,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著遗契,像睡著了一般辐棒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上牍蜂,一...
    開(kāi)封第一講書(shū)人閱讀 49,036評(píng)論 1 285
  • 那天漾根,我揣著相機(jī)與錄音,去河邊找鬼鲫竞。 笑死辐怕,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的从绘。 我是一名探鬼主播寄疏,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼僵井!你這毒婦竟也來(lái)了陕截?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤批什,失蹤者是張志新(化名)和其女友劉穎农曲,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體驻债,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡乳规,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了却汉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片驯妄。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡荷并,死狀恐怖合砂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情源织,我是刑警寧澤翩伪,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站谈息,受9級(jí)特大地震影響缘屹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜侠仇,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一轻姿、第九天 我趴在偏房一處隱蔽的房頂上張望犁珠。 院中可真熱鬧,春花似錦互亮、人聲如沸犁享。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)炊昆。三九已至,卻和暖如春威根,著一層夾襖步出監(jiān)牢的瞬間凤巨,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工洛搀, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留敢茁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓留美,卻偏偏與公主長(zhǎng)得像卷要,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子独榴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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