源碼閱讀計(jì)劃 - LiveData

LiveData是Jetpack里一個(gè)十分常用的組件,它是一個(gè)可以被觀察的數(shù)據(jù)源。能夠感知 Activity等的生命周期,在onStart或者onResume的時(shí)候才會(huì)回調(diào)監(jiān)聽。

這里舉個(gè)簡單的例子,我們?cè)贏ctivity中可以使用DataSource的observe方法去監(jiān)聽內(nèi)部數(shù)據(jù)的改變,直接修改TextView,因?yàn)檫@個(gè)方法是回調(diào)在主線程的。而且可以看到DataSource里面是沒有解注冊(cè)的方法的,原因是LiveData會(huì)幫我們自動(dòng)在LifecycleOwner的onDestory的時(shí)候解注冊(cè):

class DataSource {
    private val liveData = MutableLiveData<Int>()

    fun observe(owner: LifecycleOwner, observer: Observer<Int>) {
        liveData.observe(owner, observer)
    }

    fun loadData() {
        Thread(Runnable {
            // 加載數(shù)據(jù)
            //liveData.value = 123 // 主線程中
            liveData.postValue(123) // 子線程中
        }).start()
    }
}

// Activity中監(jiān)聽
dataSource.observe(this, Observer {data->
    textView.text = "data = ${data}"
})

知道用法之后我們來看看原理,瞧一瞧它是如何實(shí)現(xiàn)的。

注冊(cè)監(jiān)聽

private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
            new SafeIterableMap<>();

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    // 判斷主線程  
    assertMainThread("observe");

    // 判斷是否已經(jīng)DESTROYED
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        return;
    }

    // 創(chuàng)建LifecycleBoundObserver
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
  

    // 判斷是否已經(jīng)添加過監(jiān)聽,如果沒有就丟入mObservers這個(gè)map中保存
    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;
    }

    // 向Lifecycle注冊(cè)監(jiān)聽
    owner.getLifecycle().addObserver(wrapper);
}   

首先是注冊(cè)監(jiān)聽,這個(gè)代碼十分簡單,具體可以看我寫的注釋。它最核心的功能就是最后的向Lifecycle注冊(cè)監(jiān)聽。

數(shù)據(jù)更新與通知

注冊(cè)完監(jiān)聽之后我們看看數(shù)據(jù)的更新部分,如果在主線程的話直接調(diào)用LiveData的setValue方法即可更新數(shù)據(jù):

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

這個(gè)方法邏輯也很清晰,總共四行就做了四件事情:

  1. 判斷主線程
  2. 更新數(shù)據(jù)版本
  3. 更新數(shù)據(jù)
  4. 分發(fā)更新事件

dispatchingValue里面判斷傳入的initiator是否為空,如果不為空則只通知該observer,否則通知所有的observer:

void dispatchingValue(@Nullable ObserverWrapper initiator) {
    ...

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

considerNotify方法也比較易懂,就是判斷Observer是否已經(jīng)激活,如果沒有激活就返回。如果激活了再判斷observer是否已經(jīng)接收到最后一次修改數(shù)據(jù)的事件(反正Activity反復(fù)切換的時(shí)候重復(fù)通知),如果沒有就調(diào)用onChanged方法通知。

private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) {
        return;
    }
    
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    observer.mObserver.onChanged((T) mData);
}

這里的Active判斷其實(shí)判斷的observer的owner的是否至少是onStart的:

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

生命周期感知

也就是說如果Activity是在后臺(tái)的,那么setValue的時(shí)候就不會(huì)去通知observer,這就是LiveData的生命周期感知機(jī)制。那么這個(gè)消息是否就丟失了呢?當(dāng)然不是。

還記得observe方法里面向Lifecycle注冊(cè)了監(jiān)聽嗎:

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    ...
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    ...
    owner.getLifecycle().addObserver(wrapper);
}   

在Activity走到各個(gè)生命周期的時(shí)候LifeCycle就會(huì)回調(diào)LifecycleBoundObserver的onStateChanged方法:

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

在這里面做兩件事情:

  1. 判斷owner是否已經(jīng)destroy了,如果是就自動(dòng)解除監(jiān)聽
  2. 如果沒有destroy就修改激活狀態(tài)

如果是start或者resume的activeStateChanged里面就會(huì)進(jìn)行事件方法:

void activeStateChanged(boolean newActive) {
    ...
    mActive = newActive;
    ...
    if (mActive) {
        dispatchingValue(this);
    }
}

dispatchingValue方法上面講過,在這里會(huì)調(diào)用considerNotify去單獨(dú)分發(fā)給initiator。:

void dispatchingValue(@Nullable ObserverWrapper initiator) {
    ...

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

于是observer就能監(jiān)聽到onStart之前發(fā)送的消息了。

粘性事件

LiveData的事件都是粘性事件,什么是粘性事件呢?簡單來講就是注冊(cè)的監(jiān)聽可以接收到注冊(cè)之前的事件:

class DataSource {
    private val liveData = MutableLiveData<Int>()

    fun observe(owner: LifecycleOwner, observer: Observer<Int>) {
        liveData.observe(owner, observer)
    }

    fun loadData() {
        liveData.value = 123
    }
}

// Activity
override fun onResume() {
    super.onResume()
        // 先發(fā)送
    dataSource.loadData()
        // 再注冊(cè)
    dataSource.observe(this, Observer { data ->
        Log.d("testtest", "data = ${data}")
    })
}

這個(gè)其實(shí)結(jié)合上面的更新流程,去到considerNotify里面只要mLastVersion小于LiverData.mVersion就會(huì)被通知

private void considerNotify(ObserverWrapper observer) {
    ...
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    observer.mObserver.onChanged((T) mData);
}

而在創(chuàng)建ObserverWrapper的時(shí)候mLastVersion初始化是-1:

public abstract class LiveData<T> {
    ...
    static final int START_VERSION = -1;
    ...
    private abstract class ObserverWrapper {
        ...
        int mLastVersion = START_VERSION;
        ...
    }
    ...
}

于是注冊(cè)的時(shí)候就會(huì)直接通知到LiveData之前設(shè)置的數(shù)據(jù)了。

實(shí)現(xiàn)非粘性事件

如果我們不想要這個(gè)粘性事件要怎么做呢?從根本原因上來講是因?yàn)閛bserve創(chuàng)建ObserverWrapper的時(shí)候mLastVersion直接設(shè)置成了-1,所以在分發(fā)的時(shí)候肯定會(huì)被分發(fā)一次。也就是說只要我們?cè)趧?chuàng)建的時(shí)候?qū)LastVersion設(shè)置成當(dāng)前LiveData的mVersion就能避免了。

但是無論mLastVersion還是mVersion都是沒有對(duì)外公開的,所以很容易想到繼承LiveData在observe的時(shí)候反射去修改mLastVersion。但是反射的代碼比較惡心,我就不貼出來了。我這里再提供另外一種思路:

class MyLiveData<T> : LiveData<T>() {
    var version = -1

    public override fun setValue(value: T) {
        version++
        super.setValue(value)
    }

    override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
        super.observe(owner, ObserverWrapper(observer, version))
    }

    private inner class ObserverWrapper<T>(
        private val observer: Observer<in T>,
        private var version: Int
    ) :
        Observer<T> {
        override fun onChanged(t: T) {
            if (this.version < this@MyLiveData.version) {
                observer.onChanged(t)
            }

            this.version = this@MyLiveData.version
        }
    }
}

代碼很簡單,我們自己使用裝飾器模式再包裝了一層維護(hù)了LiveData的version和Observer的version進(jìn)行判斷。

postValue

在上面我們看到setValue是會(huì)判斷主線程的:

protected void setValue(T value) {
    assertMainThread("setValue");
    ...
}

如果我們?cè)谧泳€程里面想要修改數(shù)據(jù)需要使用postValue:

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

private final Runnable mPostValueRunnable = new Runnable() {
    public void run() {
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        setValue((T) newValue);
    }
};

它的原理其實(shí)很簡單,將value保存到mPendingData,然后用postToMainThread(最底層其實(shí)是Handler.post)將mPostValueRunnable丟到主線程執(zhí)行setValue(mPendingData)方法.

而且在postValue會(huì)判斷之前是否有設(shè)置過mPendingData,如果有代表已經(jīng)post過Runnable,于是就不再post第二個(gè),也就是說最多只有一個(gè)Runnable會(huì)被post。

于是這就有個(gè)問題了,就是在子線程中多次postValue,只有最后一個(gè)value會(huì)在主線程中最終設(shè)置。

但其實(shí)這個(gè)也并不是什么問題,大多數(shù)情況下主線程其實(shí)并不關(guān)心數(shù)據(jù)是如何一步步更新的,只關(guān)心最終的結(jié)果。

observeForever

observe注冊(cè)的觀察者都是生命周期感知的,如果不是start活著resume狀態(tài)的話是不能立馬接收到消息的。如果我們需要非生命周期感知的話可以使用observeForever方法,里面創(chuàng)建的是AlwaysActiveObserver而不是observe里看到的LifecycleBoundObserver:

public void observeForever(@NonNull Observer<? super T> observer) {
    ...
    AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
    ...
}

它的特點(diǎn)在于shouldBeActive永遠(yuǎn)是true:

private class AlwaysActiveObserver extends ObserverWrapper {
    ...
    @Override
    boolean shouldBeActive() {
        return true;
    }
}

這就意味著considerNotify里面肯定會(huì)繼續(xù)往下走到version判斷那里,不會(huì)因?yàn)樯芷诙崆敖Y(jié)束:

private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) {
        return;
    }
    if (!observer.shouldBeActive()) { // AlwaysActiveObserver永遠(yuǎn)為true
        observer.activeStateChanged(false);
        return;
    }
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    observer.mObserver.onChanged((T) mData);
}
?著作權(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),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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