Jetpack之LiveData

Jetpack之LiveData

1. 介紹

LiveData 具有生命周期感知能力,學(xué)習(xí)LiveData之前最好了解一下Lifecycle的知識(shí)廊散,以下是來自官網(wǎng)的介紹:

LiveData 是一種可觀察的數(shù)據(jù)存儲(chǔ)器類。與常規(guī)的可觀察類不同衔瓮,LiveData 具有生命周期感知能力见擦,意指它遵循其他應(yīng)用組件(如 Activity、Fragment 或 Service)的生命周期议蟆。這種感知能力可確保 LiveData 僅更新處于活躍生命周期狀態(tài)的應(yīng)用組件觀察者。 如果觀察者(由 Observer 類表示)的生命周期處于 STARTED 或 RESUMED 狀態(tài)萎战,則 LiveData 會(huì)認(rèn)為該觀察者處于活躍狀態(tài)咐容。LiveData 只會(huì)將更新通知給活躍的觀察者。為觀察 LiveData 對(duì)象而注冊(cè)的非活躍觀察者不會(huì)收到更改通知蚂维。

使用 LiveData 具有以下優(yōu)勢(shì):

  1. 確保界面符合數(shù)據(jù)狀態(tài) LiveData 遵循觀察者模式戳粒。當(dāng)?shù)讓訑?shù)據(jù)發(fā)生變化時(shí),LiveData 會(huì)通知 Observer 對(duì)象虫啥。您可以整合代碼以在這些 Observer 對(duì)象中更新界面蔚约。這樣一來,您無需在每次應(yīng)用數(shù)據(jù)發(fā)生變化時(shí)更新界面涂籽,因?yàn)橛^察者會(huì)替您完成更新苹祟。

  2. 不會(huì)發(fā)生內(nèi)存泄漏 觀察者會(huì)綁定到 Lifecycle 對(duì)象,并在其關(guān)聯(lián)的生命周期遭到銷毀后進(jìn)行自我清理评雌。

  3. 不會(huì)因 Activity 停止而導(dǎo)致崩潰 如果觀察者的生命周期處于非活躍狀態(tài)(如返回棧中的 Activity)树枫,則它不會(huì)接收任何 LiveData 事件。

  4. 不再需要手動(dòng)處理生命周期 界面組件只是觀察相關(guān)數(shù)據(jù)景东,不會(huì)停止或恢復(fù)觀察砂轻。LiveData 將自動(dòng)管理所有這些操作,因?yàn)樗谟^察時(shí)可以感知相關(guān)的生命周期狀態(tài)變化斤吐。

  5. 數(shù)據(jù)始終保持最新狀態(tài) 如果生命周期變?yōu)榉腔钴S狀態(tài)搔涝,它會(huì)在再次變?yōu)榛钴S狀態(tài)時(shí)接收最新的數(shù)據(jù)厨喂。例如,曾經(jīng)在后臺(tái)的 Activity 會(huì)在返回前臺(tái)后立即接收最新的數(shù)據(jù)庄呈。

  6. 適當(dāng)?shù)呐渲酶? 如果由于配置更改(如設(shè)備旋轉(zhuǎn))而重新創(chuàng)建了 Activity 或 Fragment蜕煌,它會(huì)立即接收最新的可用數(shù)據(jù)。

  7. 共享資源 您可以使用單例模式擴(kuò)展 LiveData 對(duì)象以封裝系統(tǒng)服務(wù)诬留,以便在應(yīng)用中共享它們幌绍。LiveData 對(duì)象連接到系統(tǒng)服務(wù)一次,然后需要相應(yīng)資源的任何觀察者只需觀察 LiveData 對(duì)象故响。

2. 使用

使用LiveData分為創(chuàng)建傀广、監(jiān)聽(觀察)、通知(更新)三個(gè)步驟:

  1. 創(chuàng)建 LiveData 對(duì)象 LiveData 是一種可用于任何數(shù)據(jù)的封裝容器彩届,其中包括可實(shí)現(xiàn) Collections 的對(duì)象伪冰,如 List。LiveData 對(duì)象通常存儲(chǔ)在 ViewModel 對(duì)象中樟蠕,并可通過 getter 方法進(jìn)行訪問贮聂,如以下示例中所示:
class NameViewModel : ViewModel() {
    // 創(chuàng)建一個(gè)String類型的LiveData
    val currentName: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }
}

最初,LiveData 對(duì)象中的數(shù)據(jù)并未經(jīng)過設(shè)置寨辩。

注意:請(qǐng)確保用于更新界面的 LiveData 對(duì)象存儲(chǔ)在 ViewModel 對(duì)象中吓懈,而不是將其存儲(chǔ)在 Activity 或 Fragment 中,原因如下:

  • 避免 Activity 和 Fragment 過于龐大∶夷現(xiàn)在耻警,這些界面控制器負(fù)責(zé)顯示數(shù)據(jù),但不負(fù)責(zé)存儲(chǔ)數(shù)據(jù)狀態(tài)甸怕。
  • 將 LiveData 實(shí)例與特定的 Activity 或 Fragment 實(shí)例分離開甘穿,并使 LiveData 對(duì)象在配置更改后繼續(xù)存在。
  1. 觀察 LiveData 對(duì)象 在大多數(shù)情況下梢杭,應(yīng)用組件的 onCreate() 方法是開始觀察 LiveData 對(duì)象的正確著手點(diǎn)温兼,原因如下:
  • 確保系統(tǒng)不會(huì)從 Activity 或 Fragment 的 onResume() 方法進(jìn)行冗余調(diào)用。
  • 確保 Activity 或 Fragment 變?yōu)榛钴S狀態(tài)后具有可以立即顯示的數(shù)據(jù)武契。一旦應(yīng)用組件處于 STARTED 狀態(tài)募判,就會(huì)從它正在觀察的 LiveData 對(duì)象接收最新值。只有在設(shè)置了要觀察的 LiveData 對(duì)象時(shí)咒唆,才會(huì)發(fā)生這種情況届垫。

通常,LiveData 僅在數(shù)據(jù)發(fā)生更改時(shí)才發(fā)送更新钧排,并且僅發(fā)送給活躍觀察者敦腔。此行為的一種例外情況是均澳,觀察者從非活躍狀態(tài)更改為活躍狀態(tài)時(shí)也會(huì)收到更新恨溜。此外符衔,如果觀察者第二次從非活躍狀態(tài)更改為活躍狀態(tài),則只有在自上次變?yōu)榛钴S狀態(tài)以來值發(fā)生了更改時(shí)糟袁,它才會(huì)收到更新判族。 以下示例代碼說明了如何開始觀察 LiveData 對(duì)象:

class NameActivity : AppCompatActivity() {

    // 'by viewModels()'是 activity-ktx 組件,使用 ViewModelProvider 初始化NameViewModel也可以
    private val model: NameViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 省略其他代碼...
        // 創(chuàng)建更新UI的觀察者
        val nameObserver = Observer<String> { newName ->
            // 更新UI项戴,這里是TextView的文本內(nèi)容
            nameTextView.text = newName
        }
        // 觀察LiveData形帮,將this作為LifecycleOwner和觀察者傳入。 
        model.currentName.observe(this, nameObserver)
    }
}

在傳遞 nameObserver 參數(shù)的情況下調(diào)用 observe()后周叮,系統(tǒng)會(huì)立即調(diào)用onChanged()辩撑,從而提供 mCurrentName 中存儲(chǔ)的最新值。如果 LiveData 對(duì)象尚未在 mCurrentName 中設(shè)置值仿耽,則不會(huì)調(diào)用 onChanged()合冀。

這句話的意思是, nameObserver 先改變?cè)俦O(jiān)聽(觀察)项贺,依舊可以觀察到改變后的數(shù)據(jù)君躺,即LiveData是有粘性的。

  1. 更新 LiveData 對(duì)象 LiveData 沒有公開可用的方法來更新存儲(chǔ)的數(shù)據(jù)开缎。MutableLiveData 類將公開 setValue(T)postValue(T) 方法棕叫,如果您需要修改存儲(chǔ)在 LiveData對(duì)象中的值,則必須使用這些方法奕删。通常情況下會(huì)在ViewModel中使用 MutableLiveData俺泣,然后 ViewModel 只會(huì)向觀察者公開不可變的 LiveData 對(duì)象。

設(shè)置觀察者關(guān)系后完残,您可以更新LiveData 對(duì)象的值(如以下示例中所示)砌滞,這樣當(dāng)用戶點(diǎn)按某個(gè)按鈕時(shí)會(huì)觸發(fā)所有觀察者:

button.setOnClickListener {
    val anotherName = "John Doe"
    model.currentName.setValue(anotherName)
}

在本示例中調(diào)用 setValue(T) 導(dǎo)致觀察者使用值John Doe 調(diào)用其 onChanged() 方法。本示例中演示的是按下按鈕的方法坏怪,但也可以出于各種各樣的原因調(diào)用 setValue()postValue() 來更新 mName贝润,這些原因包括響應(yīng)網(wǎng)絡(luò)請(qǐng)求或數(shù)據(jù)庫加載完成。在所有情況下铝宵,調(diào)用 setValue()postValue() 都會(huì)觸發(fā)觀察者并更新界面打掘。

注意:您必須調(diào)用 setValue(T) 方法以從主線程更新 LiveData 對(duì)象。如果在工作器線程中執(zhí)行代碼鹏秋,您可以改用 postValue(T) 方法來更新 LiveData 對(duì)象尊蚁。

3. 分析

基于androidx.lifecycle:lifecycle-livedata-core:2.3.1

根據(jù)前面的介紹,思考幾個(gè)問題:

  1. LiveData如何做到僅更新處于活躍生命周期狀態(tài)的應(yīng)用組件觀察者侣夷?

  2. LiveData粘性效果是怎么實(shí)現(xiàn)的横朋?能否去掉?如何去掉粘性效果百拓?

  3. LiveData中的setValue(T)和postValue(T)有什么區(qū)別琴锭?內(nèi)部分別怎么實(shí)現(xiàn)的晰甚?

3.1 LiveData的相關(guān)類和結(jié)構(gòu)

首先看一下源碼包,基于androidx.lifecycle:lifecycle-livedata-core:2.3.1

livedata-package.png

可以看到源碼包中的類出奇的少决帖,但是其內(nèi)部用到了Lifecycle的相關(guān)類厕九,看一下類圖:

LiveData.png

LiveData本身是一個(gè)很簡單的觀察者模式,通過observe(LifecycleOwner owner, @Observer<? super T> observer)方法向其成員變量SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers添加觀察者地回,在數(shù)據(jù)發(fā)生改變時(shí)調(diào)用setValut(T)postValue(T)來通知觀察者發(fā)生數(shù)據(jù)改變扁远。

那么LiveData如何做到僅更新處于活躍生命周期狀態(tài)的應(yīng)用組件觀察者,原理也比較簡單刻像,維護(hù)一個(gè)成員變量boolean mActive畅买,在通知觀察者之前判斷該變量為true時(shí)則通知,否則不通知细睡。而boolean mActive表示了觀察者當(dāng)前是否為活躍狀態(tài)皮获,這個(gè)狀態(tài)的改變則依賴于Lifecycle生命周期組件。

  • Observer

Observer只有一個(gè)方法的觀察者纹冤,LiveData發(fā)生變化時(shí)通知的就是它洒宝。

  • LiveData

關(guān)鍵類,所有關(guān)鍵源碼也基本上在這個(gè)類里萌京,后面分析源碼時(shí)詳細(xì)講解:

  • 內(nèi)部維護(hù)了觀察者列表雁歌、提供了添加觀察者的方法、數(shù)據(jù)更新方法(通知觀察者)知残;

  • 一個(gè)內(nèi)部抽象類ObserverWrapper靠瞎,關(guān)鍵變量boolean mActive由它維護(hù);

  • 兩個(gè)內(nèi)部類LifecycleBoundObserverAlwaysActiveObserver求妹,類圖中有說明區(qū)別乏盐;

  • MutableLiveData

由于LiveData中的 setValue(T)postValue(T)protected,外部無法訪問制恍,那么該怎么更新內(nèi)容呢父能?Android提供了MutableLiveData,該類目前也只有一個(gè)作用净神,即將 setValue(T)postValue(T) 方法公開public何吝。

LifecycleObserverLifecycleEventObserverLifecycle的知識(shí),這里不想詳細(xì)講解鹃唯,可以查看Jetpack之Lifecycle

3.2 源碼分析

了解了這幾個(gè)類的基本關(guān)系爱榕,接下來重點(diǎn)分析一下LiveData,根據(jù)使用的三步來分析第一步:創(chuàng)建LiveData

3.2.1 創(chuàng)建過程分析
public abstract class LiveData<T> {
    // liveData持有的數(shù)據(jù)
    private volatile Object mData;
    // mVersion可以理解為mData的版本坡慌,即更新次數(shù)黔酥,會(huì)作為是否通知觀察者的判斷依據(jù);只增不減
    private int mVersion;
    // 初始默認(rèn)版本
    static final int START_VERSION = -1;
    // 空對(duì)象
    static final Object NOT_SET = new Object();
    
    // 帶參構(gòu)造函數(shù),同時(shí)mVersion版本 +1
    public LiveData(T value) {
        mData = value;
        mVersion = START_VERSION + 1;
    }

    // 無參構(gòu)造函數(shù)跪者,mData賦值默認(rèn)數(shù)據(jù)棵帽,mVersion為初始版本
    public LiveData() {
        mData = NOT_SET;
        mVersion = START_VERSION;
    }
}
3.2.2 監(jiān)聽(觀察)過程分析
(1)注冊(cè)觀察者

LiveData提供了兩個(gè)觀察方法observe(...)observeForever(...),其中observeForever(...)與生命周期無關(guān)也比較簡單坑夯,看一下LiveData關(guān)于該方法的源碼:

public abstract class LiveData<T> {
    // 觀察者集合
    private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>();
    // 該方法必須在主線程調(diào)用
    @MainThread
    public void observeForever(@NonNull Observer<? super T> observer) {
        // 判斷是否在主線程,若不在則拋異常
        assertMainThread("observeForever");
        // 將觀察者包裝到AlwaysActiveObserver
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        // 將包裝后的觀察者添加到觀察者列表中抡四;若已添加則返回該對(duì)象柜蜈,若未添加在則添加并返回為空
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        // 如果觀察者為LifecycleBoundObserver則拋異常,同一個(gè)觀察者observer不能被包裝2次指巡,
        if (existing instanceof LiveData.LifecycleBoundObserver) {
            // 翻譯一下:不能添加具有不同生命周期的同一個(gè)觀察者 
            throw new IllegalArgumentException("Cannot add the same observer with different lifecycles");
        }
        // 如果不為空則表示添加過(mObservers內(nèi)已存在)淑履,直接返回;為空則表示第一次添加藻雪,需要執(zhí)行后面的邏輯
        if (existing != null) {
            return;
        }
        // 此處為第1中情況調(diào)用activeStateChanged()方法
        // * 狀態(tài)改變秘噪,正是由于這句代碼帶來了粘性效果;由于該類沒有關(guān)聯(lián)生命周期所以默認(rèn)觀察者始終處于活躍狀態(tài)勉耀,故直接調(diào)用并傳遞 true
        wrapper.activeStateChanged(true);
    }
    
    private abstract class ObserverWrapper {
        // 被包裝的觀察者
        final Observer<? super T> mObserver;
        // 觀察者是否處于或者狀態(tài)的標(biāo)記變量
        boolean mActive;
        // 觀察者觀察到的數(shù)據(jù)版本
        int mLastVersion = START_VERSION;
        // other code ...
        // 該方法作用類似于mActive指煎,但比mActive更精確;由子類實(shí)現(xiàn)
        abstract boolean shouldBeActive();
        
        // 是否關(guān)聯(lián)到入?yún)⒌纳芷诒愠猓荒J(rèn)為false
        boolean isAttachedTo(LifecycleOwner owner) {
            return false;
        }
        
        // 解除觀察者
        void detachObserver() {
        }
        
        // 有4種情況會(huì)調(diào)用該方法:1.observeForever初次添加觀察者時(shí)至壤;2.數(shù)據(jù)變更時(shí);3.移除觀察者時(shí)枢纠;4.生命周期改變時(shí)像街;
        void activeStateChanged(boolean newActive) {
            // 新狀態(tài)和當(dāng)前狀態(tài)一致則不處理
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive owner
            // 翻譯一下:立即設(shè)置活動(dòng)狀態(tài),這樣我們就不會(huì)將任何東西分派給不活動(dòng)的所有者 
            // 意思是:先改狀態(tài)后分發(fā)晋渺,為什么不是先分發(fā)再改狀態(tài)呢镰绎?
            // 舉例舊狀態(tài)為true新狀態(tài)為false,先分發(fā)的情況下木西,mActive還未被賦予新狀態(tài)畴栖,此時(shí)仍是ture,則同樣會(huì)執(zhí)行dispatchingValue()方法八千,若先賦值則不存在該情況
            mActive = newActive;
            // 調(diào)用外部類的方法驶臊,內(nèi)部會(huì)經(jīng)過判斷調(diào)用liveData 的 onActive()或onInactive()方法,表示當(dāng)前觀察者是否處于活躍狀態(tài)
            changeActiveCounter(mActive ? 1 : -1);
            // 若狀態(tài)未活躍叼丑,則分發(fā)數(shù)據(jù)
            if (mActive) {
                // * 分發(fā)數(shù)據(jù)
                dispatchingValue(this);
            }
        }
    }
    
    // 該類未覆蓋父類的 detachObserver() 方法
    private class AlwaysActiveObserver extends ObserverWrapper {

        AlwaysActiveObserver(Observer<? super T> observer) {
            super(observer);
        }

        // 這里固定返回為ture关翎,即表示觀察者一直為活躍狀態(tài)
        @Override
        boolean shouldBeActive() {
            return true;
        }
    }
}

上面分析了observeForever(...)方法,注意activeStateChanged(boolean newActive)有4種情況會(huì)調(diào)用:

  1. observeForever初次添加觀察者時(shí)(上已經(jīng)介紹鸠信,粘性效果的關(guān)鍵)

  2. 數(shù)據(jù)變更時(shí)纵寝,根據(jù)實(shí)時(shí)狀態(tài)判斷調(diào)用

  3. 移除觀察者時(shí)

  4. 觀察者生命周期改變時(shí)

這里記住在無關(guān)聯(lián)生命周期的方法observeForever(...)的內(nèi)部會(huì)調(diào)用到dispatchingValue(this)方法;

接下來看一下看一下LiveData關(guān)于observe()方法的源碼:

public abstract class LiveData<T> {
    // 觀察者集合
    private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>();
    // 該方法必須在主線程調(diào)用;接收生命周期持有者和觀察者2個(gè)參數(shù)
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        // 判斷是否在主線程爽茴,若不在則拋異常
        assertMainThread("observe");
        // 判斷需要關(guān)聯(lián)的生命周期持有的狀態(tài)葬凳,如果為DESTROYED狀態(tài)則不處理;即已經(jīng)銷毀的觀察者沒有必要再觀察數(shù)據(jù)
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        // 將觀察者包裝到 LifecycleBoundObserver
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        // 將包裝后的觀察者添加到觀察者列表中室奏;若已添加則返回該對(duì)象火焰,若未添加在則添加并返回為空
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        // mObservers內(nèi)已存在并且不是同一生命周期持有者則拋異常;即同一觀察者不能關(guān)聯(lián)不同的生命周期持有者
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer with different lifecycles");
        }
        // 如果不為空則表示添加過(mObservers內(nèi)已存在)胧沫,直接返回昌简;為空則表示第1次添加,需要執(zhí)行后面的邏輯
        if (existing != null) {
            return;
        }
        // 第1次添加該觀察者绒怨,則將其與生命周期關(guān)聯(lián)
        owner.getLifecycle().addObserver(wrapper);
    }
    
    
    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;
        // 省略其他代碼
        // 判斷觀察者狀態(tài)是否為活躍狀態(tài)纯赎;LiveData 感知生命周期的關(guān)鍵也是這里
        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        // 當(dāng)生命周期組件(Activity、Fragment等)狀態(tài)發(fā)生改變時(shí)(create南蹂、resume等)會(huì)觸發(fā)該方法犬金;更多內(nèi)容需了解Lifycycle知識(shí)
        // observe()是在onCreate時(shí)調(diào)用,而observe()內(nèi)部添加了生命周期變化的感知能力六剥。那么在Lifecycle.Event為onCrate時(shí)晚顷,這里是否能接收到回調(diào)呢?答案是可的疗疟,因?yàn)閛nCrate事件是在Activity等執(zhí)行完之后音同,才會(huì)通知觀察者
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                                   @NonNull Lifecycle.Event event) {
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            // 生命周期處于DESTROYED時(shí),移除觀察者并返回秃嗜;而其他狀態(tài)則會(huì)繼續(xù)執(zhí)行
            if (currentState == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            // 這里的 currentState 和 prevState 都為局部變量权均;為什么要?jiǎng)?chuàng)建prevState并賦值呢?了解的小伙伴指導(dǎo)一下...
            Lifecycle.State prevState = null;
            while (prevState != currentState) {
                prevState = currentState;
                // * 這里是第4種情況下調(diào)用activeStateChanged()方法锅锨,若數(shù)據(jù)已經(jīng)發(fā)生變化叽赊,即使剛剛添加的觀察者也可以收到新數(shù)據(jù)(LiveData的粘性效果)
                activeStateChanged(shouldBeActive());
                currentState = mOwner.getLifecycle().getCurrentState();
            }
        }

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

        // 解除觀察者
        @Override
        void detachObserver() {
            // 從生命周期中移除觀察者
            mOwner.getLifecycle().removeObserver(this);
        }
    }
}

LiveData感知生命周期的能力關(guān)鍵在于owner.getLifecycle().addObserver(wrapper);,上面分析了觀察者生命周期改變時(shí)會(huì)調(diào)用activeStateChanged()方法必搞,且在Activity的onCreate中添加觀察者依舊可以接收到改變后的數(shù)據(jù)(粘性效果)必指。

總結(jié)一下注冊(cè)觀察者:在注冊(cè)觀察者時(shí)會(huì)根據(jù)調(diào)用不同的方法將觀察者包裝到不同的wapper中,添加到觀察者集合里恕洲,并調(diào)用分發(fā)數(shù)據(jù)方法通知觀察者最新數(shù)據(jù)(若有)塔橡,達(dá)到粘性效果。

(2)dispatchingValue(...)分析

上面分析了2種調(diào)用activeStateChanged(boolean newActive)的情況:

  1. observeForever初次添加觀察者時(shí)
  1. 觀察者生命周期改變時(shí)

接下來分析一下該方法內(nèi)部的關(guān)鍵方法dispatchingValue()霜第,該方法在setValue()方法內(nèi)也會(huì)調(diào)用葛家。

public abstract class LiveData<T> {
    @SuppressWarnings("WeakerAccess") /* synthetic access */
    /*
    * 分發(fā)數(shù)據(jù),在數(shù)據(jù)發(fā)生改變或生命周期發(fā)生改變等情況下會(huì)調(diào)用該方法
    * 接收一個(gè)觀察者參數(shù)
    */
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            // 若傳入的指定觀察者不為空則通知指定觀察者
            if (initiator != null) {
                // 通知觀察者
                considerNotify(initiator);
                initiator = null;
            } else {
                // 若傳入的指定觀察者為空泌类,則通知觀察者集合(mObservers)里面的所有觀察者
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                     mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    // 通知觀察者
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }
    
    // 通知觀察者
    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.
        // 直譯:也許它改變了狀態(tài)癞谒,但我們還沒有得到事件。 我們?nèi)匀皇紫葯z查[observer.active]以保持它作為事件的入口。 因此弹砚,即使觀察者移動(dòng)到活動(dòng)狀態(tài)双仍,如果我們沒有收到該事件,我們最好不要通知桌吃。 
        // 也就是說:觀察者內(nèi)部的成員變量 mActive 可能已經(jīng)改變?yōu)榛钴S狀態(tài)朱沃,但是還沒有收到生命周期組件的事件通知;即加此判斷可以保證更加準(zhǔn)確的獲取觀察者的實(shí)時(shí)狀態(tài)茅诱。
        if (!observer.shouldBeActive()) {
            // 糾正觀察者的正確狀態(tài)逗物;第2種情況調(diào)用activeStateChanged()方法
            observer.activeStateChanged(false);
            return;
        }
        // 若之前的版本號(hào)高于或等于當(dāng)前版本號(hào)則直接返回;只有當(dāng)前版本大于舊版本時(shí)才繼續(xù)執(zhí)行让簿;mVersion 該變量會(huì)在每次 setValue 時(shí) +1
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        // 通知觀察者數(shù)據(jù)已更新
        observer.mObserver.onChanged((T) mData);
    }
}
(3)注銷觀察者

注銷觀察者也有2個(gè)方法:

public abstract class LiveData<T> {
    // 移除指定觀察者
    @MainThread
    public void removeObserver(@NonNull final Observer<? super T> observer) {
        // 判斷是否在主線程敬察,不在則拋異常
        assertMainThread("removeObserver");
        // 從觀察者列表中移除
        ObserverWrapper removed = mObservers.remove(observer);
        if (removed == null) {
            return;
        }
        // 已移除的觀察者解除對(duì)生命周期組件的關(guān)聯(lián)
        removed.detachObserver();
        // 移除的觀察者置為非活躍狀態(tài)秀睛;第3種情況調(diào)用activeStateChanged()方法
        removed.activeStateChanged(false);
    }

    /**
     * 移除給定生命周期組件所關(guān)聯(lián)的所有觀察者
     */
    @SuppressWarnings("WeakerAccess")
    @MainThread
    public void removeObservers(@NonNull final LifecycleOwner owner) {
        // 判斷是否在主線程尔当,不在則拋異常
        assertMainThread("removeObservers");
        // 遍歷觀察者列表
        for (Map.Entry<Observer<? super T>, ObserverWrapper> entry : mObservers) {
            // 如果是與給定的觀察者一致,則調(diào)用 removeObserver(...)方法
            if (entry.getValue().isAttachedTo(owner)) {
                removeObserver(entry.getKey());
            }
        }
    }
}

注冊(cè)蹂安、注銷觀察者的流程就分析完了椭迎,關(guān)于前面問題提到的粘性效果在分析過程中也提到了,即在注冊(cè)觀察者時(shí)調(diào)用了通知觀察者數(shù)據(jù)改變的方法田盈。那么能否去掉粘性效果呢畜号?如何去掉?

首先通過上面的分析可以知道允瞧,在真正調(diào)用觀察者的onChange(T)之前會(huì)有3次判斷简软,可以通過改變其中1個(gè)的判斷條件即可:

// 通知觀察者
private void considerNotify(ObserverWrapper observer) {
    // 第1次判斷
    if (!observer.mActive) {
        return;
    }
    // 第2次判斷
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    // 第3次判斷
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    observer.mObserver.onChanged((T) mData);
}

前2次判斷都是和觀察者的活躍狀態(tài)有關(guān),而這個(gè)活躍狀態(tài)和生命周期相關(guān)述暂,不能輕易修改痹升。第3次判斷數(shù)據(jù)版本看起來可行,它本身就是標(biāo)記數(shù)據(jù)版本的畦韭,那么久從它下手疼蛾。

粘性效果是指:數(shù)據(jù)先發(fā)生改變,后注冊(cè)觀察者也可以收到數(shù)據(jù)改變艺配。數(shù)據(jù)發(fā)生了改變察郁,其持有的成員變量private int mVersion就大于0;而后注冊(cè)觀察者转唉,在觀察者包裝類中的成員變量被賦值為int mLastVersion = START_VERSION(-1)皮钠,observer.mLastVersion >= mVersion條件不成立,故會(huì)通知觀察者赠法。去掉粘性效果:在注冊(cè)時(shí)將mVersion的值賦值給mLastVersion即可使該條件成立鳞芙,不再通知觀察者。附上一段大神的實(shí)現(xiàn):

public class UnPeekLiveData<T> extends MutableLiveData<T> {

    @Override
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        super.observe(owner, observer);
        hook(observer);
    }

    private void hook(Observer<? super T> observer) {
        Class<LiveData> liveDataClass = LiveData.class;
        try {
            //獲取field private SafeIterableMap<Observer<T>, ObserverWrapper> mObservers
            Field mObservers = liveDataClass.getDeclaredField("mObservers");
            mObservers.setAccessible(true);
            //獲取SafeIterableMap集合mObservers
            Object observers = mObservers.get(this);
            Class<?> observersClass = observers.getClass();
            //獲取SafeIterableMap的get(Object obj)方法
            Method methodGet = observersClass.getDeclaredMethod("get", Object.class);
            methodGet.setAccessible(true);
            //獲取到observer在集合中對(duì)應(yīng)的ObserverWrapper對(duì)象
            Object objectWrapperEntry = methodGet.invoke(observers, observer);
            Object objectWrapper = null;
            if (objectWrapperEntry instanceof Map.Entry) {
                objectWrapper = ((Map.Entry) objectWrapperEntry).getValue();
            }
            if (objectWrapper == null) {
                throw new NullPointerException("ObserverWrapper can not be null");
            }
            //獲取ObserverWrapper的Class對(duì)象  LifecycleBoundObserver extends ObserverWrapper
            Class<?> wrapperClass = objectWrapper.getClass().getSuperclass();
            //獲取ObserverWrapper的field mLastVersion
            Field mLastVersion = wrapperClass.getDeclaredField("mLastVersion");
            mLastVersion.setAccessible(true);
            //獲取liveData的field mVersion
            Field mVersion = liveDataClass.getDeclaredField("mVersion");
            mVersion.setAccessible(true);
            Object mV = mVersion.get(this);
            //把當(dāng)前ListData的mVersion賦值給 ObserverWrapper的field mLastVersion
            mLastVersion.set(objectWrapper, mV);

            mObservers.setAccessible(false);
            methodGet.setAccessible(false);
            mLastVersion.setAccessible(false);
            mVersion.setAccessible(false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
3.2.3 更新 LiveData 對(duì)象分析

分析一下更新LiveData持有的數(shù)據(jù)源碼:

public abstract class LiveData<T> {
    // 延遲的數(shù)據(jù)
    volatile Object mPendingData = NOT_SET;
    private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                // 將延遲數(shù)據(jù)賦值給局部變量newValue
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            // 將newValue作為入?yún)⒄{(diào)用setValue方法
            setValue((T) newValue);
        }
    };
    // 可以在子線程調(diào)用
    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            // 將數(shù)據(jù)賦值給延遲數(shù)據(jù)mPendingData
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        // 內(nèi)部會(huì)追溯到 DefaultTaskExecutor ,是通過 Handler 實(shí)現(xiàn)的調(diào)度
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }
    
    // 必須在主線程調(diào)用
    @MainThread
    protected void setValue(T value) {
        // 判斷是否在主線程原朝,否則拋異常
        assertMainThread("setValue");
        // 數(shù)據(jù)版本 +1
        mVersion++;
        // 給數(shù)據(jù)賦值
        mData = value;
        // 分發(fā)數(shù)據(jù)驯嘱;內(nèi)部分析查看 [dispatchingValue(...)分析]
        dispatchingValue(null);
    }
}

問題:

分析如下代碼,分析觀察者收到的數(shù)據(jù)( ):

// 在主線程按如下順序調(diào)用
liveData.postValue("a");
liveData.setValue("b");

A. a
B. b
C. a b
D. b a

解析:更新了2次數(shù)據(jù)且調(diào)用的是不同方法喳坠,所以首先排除 A B 鞠评;接著分析順序,由于setValue(T)是直接通知更新壕鹉,所以觀察者會(huì)首先收到 ‘b’ 剃幌;postValue(T)是將新數(shù)據(jù)賦值給mPendingData,等到Handler調(diào)度執(zhí)行時(shí)才會(huì)調(diào)用setValue(T)mPendingData的數(shù)據(jù)通知給觀察者晾浴,故'a'后收到负乡。答案:D.
源碼注釋中還有:如果在主線程執(zhí)行提交的任務(wù)之前多次調(diào)用此方法,則只會(huì)分派最后一個(gè)值脊凰。也比較容易理解抖棘,"主線程執(zhí)行提交的任務(wù)之前多次調(diào)用此方法"mPendingData會(huì)一直被賦值為新值,在執(zhí)行調(diào)度時(shí)也只有最后一個(gè)值會(huì)被分派狸涌。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末切省,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子帕胆,更是在濱河造成了極大的恐慌朝捆,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件懒豹,死亡現(xiàn)場(chǎng)離奇詭異芙盘,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)脸秽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門儒老,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人豹储,你說我怎么就攤上這事贷盲。” “怎么了剥扣?”我有些...
    開封第一講書人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵巩剖,是天一觀的道長。 經(jīng)常有香客問我钠怯,道長佳魔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任晦炊,我火速辦了婚禮鞠鲜,結(jié)果婚禮上宁脊,老公的妹妹穿的比我還像新娘。我一直安慰自己贤姆,他們只是感情好榆苞,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著霞捡,像睡著了一般坐漏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上碧信,一...
    開封第一講書人閱讀 51,488評(píng)論 1 302
  • 那天赊琳,我揣著相機(jī)與錄音,去河邊找鬼砰碴。 笑死躏筏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的呈枉。 我是一名探鬼主播趁尼,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼碴卧!你這毒婦竟也來了弱卡?” 一聲冷哼從身側(cè)響起乃正,我...
    開封第一講書人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤住册,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后瓮具,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荧飞,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年名党,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了叹阔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡传睹,死狀恐怖耳幢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情欧啤,我是刑警寧澤睛藻,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站邢隧,受9級(jí)特大地震影響店印,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜倒慧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一按摘、第九天 我趴在偏房一處隱蔽的房頂上張望包券。 院中可真熱鬧,春花似錦炫贤、人聲如沸溅固。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽发魄。三九已至,卻和暖如春俩垃,著一層夾襖步出監(jiān)牢的瞬間励幼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來泰國打工口柳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留苹粟,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓跃闹,卻偏偏與公主長得像嵌削,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子望艺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

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