LiveData源碼解析

掘金文章鏈接

基于:
macOs:10.14/AS:3.4/Android build-tools:28.0.0

思路

看源碼前先考慮下如果要自己實(shí)現(xiàn) LiveData 應(yīng)該怎么做?

基本做法:

  1. 目標(biāo)數(shù)據(jù)私有;
  2. 開放 setter 方法用于更新目標(biāo)數(shù)據(jù);
  3. 提供方法添加數(shù)據(jù)變化監(jiān)聽器(Observer);

擴(kuò)展:

  1. 允許子線程更新數(shù)據(jù), 因此 setter 需要考慮同步;
  2. 項(xiàng)目中可能多個(gè)地方需要用到目標(biāo)數(shù)據(jù),因此回調(diào)監(jiān)聽器(Observer)需支持添加多個(gè);
  3. 遍歷通知各 Observer 更新數(shù)據(jù)期間若數(shù)據(jù)發(fā)生了變化,要如何處理;
  4. 數(shù)據(jù)變化時(shí)常常都需要更新UI,而UI有生命周期,因此 Observer 需要提供 Lifecycle 相關(guān)邏輯支持,包括:
    1. 定義處于哪些生命周期的 Observer 可以收到數(shù)據(jù)更新;
    2. onDestroy() 時(shí)自動(dòng)移除 Observer 等;
  5. 如何定義 數(shù)據(jù)變化 呢? 最簡單直接的做法是每次觸發(fā) setter 方法時(shí)都當(dāng)作數(shù)據(jù)發(fā)生了變化, 遍歷通知所有 Observer 即可, 更進(jìn)一步的判定交給調(diào)用方;
    ......

簡單使用

// 定義 livedata
object ParaConfig {
    // 定義一個(gè)私有的 `MutableLiveData`
    private val msgLiveData = MutableLiveData<String>()

    // 開放給外部獲取數(shù)據(jù)更新時(shí),提供不可變的 `LiveData` 即可;
    fun getMsgLiveData(): LiveData<String> = msgLiveData

    fun updateMsg(msg: String, inBgThread: Boolean = false) {
        if (inBgThread) {
            msgLiveData.postValue(msg) // 在子線程中更新數(shù)據(jù)
        } else {
            msgLiveData.value = msg // 在主線程中更新數(shù)據(jù)
        }
    }
}
// 添加 `Observer`
class LiveDataFrag : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // 添加一個(gè)跟生命周期相關(guān)的 `Observer`
        ParaConfig.getMsgLiveData().observe(this, Observer<String> { newMsg ->
            tv_msg.text = newMsg
        })

        // 無視生命周期, 每次數(shù)據(jù)變化時(shí)都會(huì)回調(diào),需要自行移除observer
        ParaConfig.getMsgLiveData().observeForever {
            Logger.d("observeForever: $it","tag_livedata")
        }
    }
}

看源碼我還是習(xí)慣從調(diào)用入口一步步往下看, 以下也是按照這種順序來;

實(shí)現(xiàn)

livedata

添加 Observer

// LiveData.java
public abstract class LiveData<T> {
    private static final Object NOT_SET = new Object();
    // 實(shí)際數(shù)據(jù),類型為 Object 而非 T
    private volatile Object mData = NOT_SET;
    // 存儲所有的 Observer
    private SafeIterableMap<Observer<T>, ObserverWrapper> mObservers = new SafeIterableMap<>();

    // 添加跟生命周期相關(guān)的 observer
    // 目標(biāo)數(shù)據(jù)
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
        // 若 LifecycleOwner 已處于已被銷毀,則忽略該 observer
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            return;
        }

        // 將 LifecycleOwner 和 Observer 功能進(jìn)行綁定包裝
        // 生成支持生命周期感知的 Observer: LifecycleBoundObserver
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        // 避免重復(fù)添加相同的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;
        }

        // 實(shí)現(xiàn)對 LifecycleOwner 生命周期的感知
        // 關(guān)鍵還是 LifecycleBoundObserver 類,我們馬上進(jìn)去看一下
        owner.getLifecycle().addObserver(wrapper);
    }

    // 無視生命周期, 每次數(shù)據(jù)發(fā)生變化時(shí),都會(huì)回調(diào)通知 Observer
    // 需要手動(dòng)在不需要時(shí)移除 Observer
    @MainThread
    public void observeForever(@NonNull Observer<T> observer) {
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        wrapper.activeStateChanged(true);
    }
}

MutableLiveData 只是簡單重寫了 LiveDatasetValue(T)/postValue(T) 方法, 改為 public 而已;

數(shù)據(jù)如何傳遞的: setValue(T) 解析

// LiveData.java
@MainThread
protected void setValue(T value) {
    // 只能在UI線程中調(diào)用,否則拋出異常,崩潰
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

private boolean mDispatchingValue;

// 若參數(shù) initiator 非空,則表示只通知特定的 ObserverWrapper, 否則是回調(diào)通知所有 ObserverWrapper
// 由于只在主線程中調(diào)用,因此不用做多線程處理
private void dispatchingValue(@Nullable ObserverWrapper initiator) {
    // 小技巧: 在遍歷通知各 ObserverWrapper 期間, 若數(shù)據(jù)發(fā)生了變化, 則會(huì)重新遍歷通知
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }

    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {// initiator 非空時(shí),只更新特定 ObserverWrapper
            considerNotify(initiator); // 實(shí)際更新數(shù)據(jù)的方法
            initiator = null;
        } else { // 否則遍歷更新所有 ObserverWrapper
            for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                // 若數(shù)據(jù)發(fā)生變化, 則退出for循環(huán)
                // 而外層 do...while() 判定條件為true,就會(huì)重新遍歷通知各 ObserverWrapper;
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

// 判斷是否要將數(shù)據(jù)分發(fā)到指定的 ObserverWrapper
private void considerNotify(ObserverWrapper observer) {
    // 是否可以分發(fā)數(shù)據(jù)到指定的 observer, 由 mActive 來控制
    // 所以 mActive 很重要,具體下一節(jié)解讀
    if (!observer.mActive) {
        return;
    }

    // 二次確認(rèn)狀態(tài), 可能生命周期發(fā)生了變化,但 mActive 并未改變
    if (!observer.shouldBeActive()) {
        // active -> inactive 時(shí)通知更新狀態(tài)
        // inactive 狀態(tài)下就不需要分發(fā)數(shù)據(jù)了
        observer.activeStateChanged(false);
        return;
    }

    // 若 ObserverWrapper 持有的數(shù)據(jù)值已是最新版本, 自然也不用分發(fā)
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;

    // 通知 observer 數(shù)據(jù)有更新
    // observer.mObserver 是調(diào)用方實(shí)際傳入的
    observer.mObserver.onChanged((T) mData);
}

用于子線程調(diào)用的 postValue(T) 會(huì)發(fā)射一個(gè) Runnable 到主線程中, 最終也是通過 setValue(T) 來實(shí)現(xiàn)數(shù)據(jù)分發(fā);
當(dāng)然, postValue(T) 也可以在主線程調(diào)用,不過是多此一舉,如:

// observer會(huì)先收到 "msgFromSetValue" 然后才收到 "msgFromPostValue"
someBtnView.setOnClickListener {
    msgLiveData.postValue("msgFromPostValue")
    msgLiveData.value = "msgFromSetValue"
}

ObserverWrapper 類解析

ObserverWrapper
// LiveData 的內(nèi)部抽象類
// 包裝用戶傳入的 Observer, 提供數(shù)據(jù)版本記錄以及active狀態(tài)(生命周期)判斷
private abstract class ObserverWrapper {
    final Observer<T> mObserver;
    boolean mActive; // 確定當(dāng)前 ObserverWrapper 是否生效,true時(shí)才可進(jìn)行數(shù)據(jù)更新
    int mLastVersion = START_VERSION; // 當(dāng)前持有的數(shù)據(jù)版本號,初始值為 -1

    ObserverWrapper(Observer<T> observer) {
        mObserver = observer;
    }

    // 判斷該 Observer 是否有效, true 時(shí)才會(huì)觸發(fā) activeStateChanged()
    abstract boolean shouldBeActive();

    boolean isAttachedTo(LifecycleOwner owner) {
        return false;
    }

    void detachObserver() {
    }

    // 更新本 ObserverWrapper 的狀態(tài)
    void activeStateChanged(boolean newActive) {
        // 若狀態(tài)沒變化,不需要更新,直接返回
        if (newActive == mActive) {
            return;
        }

        mActive = newActive;
        boolean wasInactive = LiveData.this.mActiveCount == 0;
        LiveData.this.mActiveCount += mActive ? 1 : -1;

        // 處于 active 狀態(tài)的 observer 數(shù)量從0 -> 1時(shí),觸發(fā) onActive() 方法
        if (wasInactive && mActive) {
            onActive();
        }

        // 處于 active 狀態(tài)的 observer 數(shù)量從 1 -> 0時(shí),觸發(fā) onInactive() 方法
        // 提供給觀察者釋放資源的機(jī)會(huì)
        if (LiveData.this.mActiveCount == 0 && !mActive) {
            onInactive();
        }

        // observer 從  inactive -> active 時(shí), 更新數(shù)據(jù)
        if (mActive) {
            // 將數(shù)據(jù)發(fā)送給該 observer
            dispatchingValue(this);
        }
    }
}

此類并未給出 inactive/active 具體是何種狀態(tài), 具體應(yīng)是由 shouldBeActive() 來確定, 因此需要從子類查找;

子類 AlwaysActiveObserver比較簡單, 只是將shouldBeActive() 固定返回 true,表示一直生效, 每次數(shù)據(jù)發(fā)生變化時(shí)都需要發(fā)送通知;
我們看下 LifecycleBoundObserver 類;

LifecycleBoundObserver 解析

// LiveData 內(nèi)部類
// 將 LifecycleObserver 和 ObserverWrapper 結(jié)合,當(dāng)生命周期變化時(shí),通知 ObserverWrapper 更新數(shù)據(jù)
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
    @NonNull final LifecycleOwner mOwner;

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

    @Override
    boolean shouldBeActive() {
        // 此處定義了哪些生命周期是 `active` 的
        // 結(jié)合 Lifecycle.State 類 ,我們知道是: STARTED/RESUMED 兩種狀態(tài)
        // 對應(yīng)于生命周期 `onStart()` 之后到 `onStop()` 之前
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    // 生命周期變化時(shí)回調(diào)本方法
    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        // 若當(dāng)前 LifecycleOwner onDestory() 了, 則自動(dòng)移除 observer, 避免內(nèi)存泄露
        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        // 將 shouldBeActive() 返回的狀態(tài)當(dāng)做本 ObserverWrapper 的狀態(tài)
        // 即  mActive = shouldBeActive()
        activeStateChanged(shouldBeActive());
    }

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

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

小結(jié)

  1. 只能在主線程中進(jìn)行 Observer 的添加:
    1. observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer)
    2. observeForever(@NonNull Observer<T> observer)
  2. 添加帶 LifecycleOwnerObserver 時(shí), 若發(fā)生 onDestory() ,則會(huì)自動(dòng)移除 Observer;
  3. 數(shù)據(jù)只會(huì)在 LifecycleOwner 處于 onStart()/onResume()/onPause() 生命周期時(shí),才會(huì)分發(fā);
  4. 若處于 active 的 Observer 數(shù)量從 1 -> 0, 回調(diào) onInactive() ,適用于子類進(jìn)行資源釋放;
  5. 若處于 active 的 Observer 數(shù)量從 0 -> 1, 回調(diào) onActive();
  6. LiveData 類和 ObserverWrapper 類都會(huì)在內(nèi)部持有一個(gè)數(shù)據(jù)版本號;
  7. LiveData 數(shù)據(jù)發(fā)生變化時(shí),會(huì)切換到主線程,然后遍歷所有 Observer, 并將數(shù)據(jù)分發(fā)給處于 active 狀態(tài)并且數(shù)據(jù)版本號不一致的 Observer;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖阵漏,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡好渠,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進(jìn)店門节视,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拳锚,“玉大人,你說我怎么就攤上這事寻行』舨簦” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵拌蜘,是天一觀的道長杆烁。 經(jīng)常有香客問我,道長简卧,這世上最難降的妖魔是什么兔魂? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮举娩,結(jié)果婚禮上析校,老公的妹妹穿的比我還像新娘。我一直安慰自己晓铆,他們只是感情好勺良,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著骄噪,像睡著了一般尚困。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上链蕊,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天事甜,我揣著相機(jī)與錄音谬泌,去河邊找鬼。 笑死逻谦,一個(gè)胖子當(dāng)著我的面吹牛掌实,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播邦马,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼贱鼻,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了滋将?” 一聲冷哼從身側(cè)響起邻悬,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎随闽,沒想到半個(gè)月后父丰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掘宪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年蛾扇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片魏滚。...
    茶點(diǎn)故事閱讀 40,146評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡镀首,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出栏赴,到底是詐尸還是另有隱情蘑斧,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布须眷,位于F島的核電站竖瘾,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏花颗。R本人自食惡果不足惜捕传,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望扩劝。 院中可真熱鬧庸论,春花似錦、人聲如沸棒呛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽簇秒。三九已至鱼喉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背扛禽。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工锋边, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人编曼。 一個(gè)月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓豆巨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親掐场。 傳聞我的和親對象是個(gè)殘疾皇子往扔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評論 2 356