Android-LiveData 解析

當(dāng)前為 2.3.1 版本

本文分析 LiveData 更新原理,涉及 LifecycleBoundObserver 綁定 Lifecycle 對生命周期變化進(jìn)行監(jiān)聽瓶蝴。

首先看 LiveData.ovserve() 方法

    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // 此處 return眨业,了解到 Glide 在 onDestroy() 后加載圖片拋出異常處理
            return;
        }
        //1. LifecycleBoundObserver 為 LifecycleObserver 
        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;
        }
        //2.  owner 獲取 Lifecycle 并跟 wrap 綁定,使得 wrapper 監(jiān)聽生命周期
        owner.getLifecycle().addObserver(wrapper);
    }

接下來看 LifecycleBoundObserver

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;

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

        @Override
        boolean shouldBeActive() {
            //對應(yīng) onStart铣耘、onPause尖殃、onResume 狀態(tài),可以查看 Lifecycle.getTargetState() 方法 對應(yīng)生命周期 state 賦值情況
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }
        //Activity\Fragment 生命周期變化會回調(diào)此方法屯耸。
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            if (currentState == DESTROYED) {
                //DESTROYED 移除監(jiān)聽
                removeObserver(mObserver);
                return;
            }
            Lifecycle.State prevState = null;
            while (prevState != currentState) {
                prevState = currentState;
                //1.1 查看 shouldBeActive() 方法拐迁,如果是 onStart onResume onPause 狀態(tài)則判定活動狀態(tài),可更新值
                //1.2 回到 ObserverWrapper.activeStateChanged() 方法
                activeStateChanged(shouldBeActive());
                currentState = mOwner.getLifecycle().getCurrentState();
            }
        }

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

        @Override
        void detachObserver() {
            //移除監(jiān)聽
            mOwner.getLifecycle().removeObserver(this);
        }
    }

ObserverWrapper.activeStateChanged 方法

   private abstract class ObserverWrapper {

        boolean mActive;
        //保存當(dāng)前的監(jiān)聽值的版本疗绣,用于跟 LiveData 的版本比較线召,小于 LiveData 值的版本則需要更新。
        int mLastVersion = START_VERSION;

        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            mActive = newActive;
            changeActiveCounter(mActive ? 1 : -1);
            //isAtLeast(STARTED)為true持痰,mActive 為 true灶搜,則繼續(xù)分發(fā) value
            if (mActive) {
                //1.3 回到 LiveData 的 dispatchingValue 方法。
                dispatchingValue(this);
            }
        }
    }

Livecycle state 賦值和活動狀態(tài)判斷如下

public abstract class Lifecycle {
        @NonNull
        public State getTargetState() {
            switch (this) {
                case ON_CREATE:
                case ON_STOP:
                    return State.CREATED;

                case ON_START:
                case ON_PAUSE:
                    //STARTED 對應(yīng) onStart工窍、onPause 生命周期
                    return State.STARTED;
                case ON_RESUME:
                     //RESUMED 對應(yīng) onResume 生命周期
                    return State.RESUMED;

                case ON_DESTROY:
                    return State.DESTROYED;
                case ON_ANY:
                    break;
            }
        }

    //對應(yīng) State 類型
    public enum State {
        DESTROYED,
        INITIALIZED,
        CREATED,
        STARTED,
        RESUMED;
        // isAtLeast(STARTED) 最小為 STARTED割卖、RESUMED 狀態(tài),對應(yīng)生命周期如上
        public boolean isAtLeast(@NonNull State state) {
            return compareTo(state) >= 0;
        }
    }
}

回到 LiveData.dispatchingValue()

    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        ...
        do {
            if (initiator != null) {
                //1.4
                considerNotify(initiator);
                initiator = null;
            } else {
                 ...
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        //重要;汲E羲荨!淹仑,observer 跟 LiveData 分別保存數(shù)據(jù)的 version 值丙挽,沒修改一次 value,則版本號 +1
        //當(dāng) LiveData 的版本號 大于 observer 的版本號匀借,則說明需要監(jiān)聽的值修改颜阐,則回調(diào)監(jiān)聽
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //1.5 回調(diào)監(jiān)聽,即完成監(jiān)聽
        observer.mObserver.onChanged((T) mData);
    }

以上流程分析了調(diào)用 observe 方法時吓肋,LiveData 內(nèi)部創(chuàng)建 LifecycleBoundObserver 對象凳怨,該對象實(shí)現(xiàn) LifecycleObserver 接口并注冊 Livecycle 實(shí)現(xiàn)對生命周期變化監(jiān)聽。
當(dāng)生命周期變化時候,在 LifecycleBoundObserver 中判斷是否在活動狀態(tài)肤舞,即 onStart紫新、onResume、onPause 狀態(tài)李剖,如果是芒率,則依次調(diào)用 dispatchingValue () -> considerNotify() 方法,當(dāng)值的 version 未改變則 return篙顺,當(dāng)判定 version 已經(jīng)改變了偶芍,則回調(diào) Observer.onChanged 完成監(jiān)聽。

下面來看主動調(diào)用 LiveData.setValue() 監(jiān)聽

    protected void setValue(T value) {
        assertMainThread("setValue");
        //版本++
        mVersion++;
        mData = value;
        //繼續(xù)分發(fā)慰安,回到上面的流程
        dispatchingValue(null);
    }

postValue 是通過 Handler 發(fā)送 Runnable 到主線程繼續(xù)執(zhí)行 setValue 的過程腋寨。

注意:
數(shù)據(jù)倒灌問題:如果先執(zhí)行 LiveData.setValue() 再調(diào)用 observe 監(jiān)聽,此時 LiveData mVersion 已經(jīng)改變?yōu)?化焕,ObserverWrapper 的 mLastVersion 還是為 -1,所以訂閱時仍會收到 onChanged 回調(diào)铃剔∪鼋埃可以使用 SingleLiveEvent 避免。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末键兜,一起剝皮案震驚了整個濱河市凤类,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌普气,老刑警劉巖谜疤,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異现诀,居然都是意外死亡夷磕,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進(jìn)店門仔沿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來坐桩,“玉大人,你說我怎么就攤上這事封锉∶圊危” “怎么了?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵成福,是天一觀的道長碾局。 經(jīng)常有香客問我,道長奴艾,這世上最難降的妖魔是什么净当? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮握侧,結(jié)果婚禮上蚯瞧,老公的妹妹穿的比我還像新娘嘿期。我一直安慰自己,他們只是感情好埋合,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布备徐。 她就那樣靜靜地躺著,像睡著了一般甚颂。 火紅的嫁衣襯著肌膚如雪蜜猾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天振诬,我揣著相機(jī)與錄音蹭睡,去河邊找鬼。 笑死赶么,一個胖子當(dāng)著我的面吹牛肩豁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播辫呻,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼清钥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了放闺?” 一聲冷哼從身側(cè)響起祟昭,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎怖侦,沒想到半個月后篡悟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡匾寝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年搬葬,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旗吁。...
    茶點(diǎn)故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡踩萎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出很钓,到底是詐尸還是另有隱情香府,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布码倦,位于F島的核電站企孩,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏袁稽。R本人自食惡果不足惜勿璃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧补疑,春花似錦歧沪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至锹杈,卻和暖如春撵孤,著一層夾襖步出監(jiān)牢的瞬間疙咸,已是汗流浹背涤浇。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留删顶,地道東北人咬清。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓闭专,卻偏偏與公主長得像,于是被迫代替她去往敵國和親枫振。 傳聞我的和親對象是個殘疾皇子喻圃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評論 2 359

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