欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android mvvm之LiveData原理案例詳解

 更新時(shí)間:2021年09月07日 14:27:51   作者:冬天的毛毛雨  
這篇文章主要介紹了Android mvvm之LiveData原理案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下

1. 生命周期感知

1.1 生命周期感知組件

我們知道,Controller(Activity or Fragment) 都是有生命周期的,但是傳統(tǒng)的 Controller 實(shí)現(xiàn)方式只負(fù)責(zé) Controller 本身的生命周期管理,而與業(yè)務(wù)層的數(shù)據(jù)之間并沒有實(shí)現(xiàn)良好解耦的生命周期事件交換。所以業(yè)務(wù)層都需要自己主動去感知 Controller 生命周期的變化,并在 Controller 的生存期處理數(shù)據(jù)的?;?,而在消亡時(shí)刻解除與 Controller 之間的關(guān)系,這種處理方式隨著業(yè)務(wù)規(guī)模的擴(kuò)大往往顯得代碼臃腫和難以維護(hù)。

Jetpack 框架讓 Controller 變得可感知,成為一個生命周期事件變化的通知中心,我們實(shí)現(xiàn)的任何組件或?qū)ο蠖伎梢酝ㄟ^訂閱這個通知中心實(shí)時(shí)知道 Controller 生命周期的變化(這樣的組件或?qū)ο笪覀兎Q之為生命周期感知組件),而不需要繁瑣的主動詢問;同時(shí),Jetpack 推薦將數(shù)據(jù)封裝成 LiveData,因?yàn)?LiveData 自帶感知 Controller 的生命周期變化,自我維護(hù)數(shù)據(jù)更新與生命周期更新的協(xié)調(diào)關(guān)系。LiveData 是典型的生命周期感知組件。而現(xiàn)在的 Controller 我們稱之為生命周期可感知 Controller,在 Jetpack 的實(shí)現(xiàn)中,有一個專門的接口來代表它——LifecycleOwner,名副其實(shí),Controller 是生命周期的所有者。

1.2 LifecycleOwner 的狀態(tài)和事件模型

LifecycleOwner 中維護(hù)一個叫做 Lifecycle 的接口,它規(guī)定了生命周期的狀態(tài)和狀態(tài)切換的事件流模型。在 android developer 的官方文檔中,給出了一個非常清晰的時(shí)序圖來說明這個模型:

lifecycle_states

  • 生命周期的狀態(tài)總共有 5 個:DESTROYED,INITIALIZED,CREATED,STARTED,RESUMED;
  • 狀態(tài)切換事件總共有 7 個:ON_CREATE,ON_START,ON_RESUME,ON_PAUSE,ON_STOP,ON_DESTROY,ON_ANY;
  • 每個事件除了 ON_ANY 以外,都嚴(yán)格在 Controller 的 onXXX() 回調(diào)中產(chǎn)生,比如 ON_CREATE 事件在 Activity.onCreate() 和 Fragment.onCreate() 中進(jìn)行分派;
  • 需要注意 CREATED 和 STARTED 兩個狀態(tài)的入度都為 2,即有兩個不同的事件都能達(dá)到這個狀態(tài)。

2. LiveData 與 LifecycleOwner 的雙向訂閱

在講述 LiveData 的原理時(shí),沒有辦法孤立地談 LiveData,因?yàn)樗膶?shí)現(xiàn)和 LifecycleOwner 的交互是分不開的,所以這里需要將兩者結(jié)合進(jìn)行說明。

2.1 LiveData 訂閱生命周期變化

LiveData 作為 View 的 UI 狀態(tài)數(shù)據(jù)源,并不是在 LifecycleOwner 的每個生命周期狀態(tài)中都可用的,而必須在 View 完成所有的測量和布局操作后,才能基于 LiveData 進(jìn)行 UI 狀態(tài)更新。這說明 LiveData 是有一個可用狀態(tài)標(biāo)記的,在源代碼中,標(biāo)記為 active:

LiveData 中更新 active 標(biāo)記的方法:

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

這說明,只有當(dāng) LifecycleOwner 的狀態(tài)至少是 STARTED,LiveData 才是處于激活狀態(tài)的。再看 Lifecycle.State 的枚舉順序:

public enum State {
    DESTROYED,
    INITIALIZED,
    CREATED,
    STARTED,
    RESUMED;

    /**
     * Compares if this State is greater or equal to the given {@code state}.
     *
     * @param state State to compare with
     * @return true if this State is greater or equal to the given {@code state}
     */
    public boolean isAtLeast(@NonNull State state) {
        return compareTo(state) >= 0;
    }
}

進(jìn)一步說明,只有當(dāng) LifecycleOwner 的狀態(tài)是 STARTED 和 RESUMED 時(shí),LiveData 才是處于激活狀態(tài)的,而只有在激活狀態(tài)下,LiveData 才會將最新數(shù)據(jù)變化通知給它的訂閱者:

private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) { // 沒有激活,不進(jìn)行通知
        return;
    }

    // 在 LifecycleOwner 的生命周期變化事件分派之前,需要提前主動更新一下激活狀態(tài),
    // 如果未激活,同樣不進(jìn)行通知
    if (!observer.shouldBeActive()) { 
        observer.activeStateChanged(false);
        return;
    }

    //...省略非關(guān)鍵代碼

    observer.mObserver.onChanged((T) mData);
}

嚴(yán)格的說這里并不應(yīng)該叫 LiveData 的激活狀態(tài),而應(yīng)該是向 LiveData 進(jìn)行訂閱的 LifecycleOwner 的激活狀態(tài),此時(shí) LifecycleOwner 作為觀察者觀察 LiveData 的變化。所以這里可能叫 LiveData 在每一個 LifecycleOwner 上的分身的激活狀態(tài)更合適,為了表述方便,我們就統(tǒng)稱叫 LiveData 的激活狀態(tài)。我們將在 2.2 節(jié)描述 LifecycleOwner 如何訂閱 LiveData。

以上,只為了說明一個問題:LiveData 需要訂閱 LifecycleOwner,感知其生命周期變化:

livedata_observe_lifecycleowner

圖示說明,LiveData 訂閱 LifecycleOwner,而由 LifecycleOwner.Lifecycle 代理完成生命周期狀態(tài)變化通知,所以 LiveData 直接能感知的是 Lifecycle。

2.2 LifecycleOwner 訂閱數(shù)據(jù)變化

LifecycleOwner 在 STARTED 和 RESUMED 的狀態(tài)下可以根據(jù) LiveData 更新 UI 的狀態(tài),所以 LifecycleOwner 需要訂閱 LiveData 的數(shù)據(jù)變化。

在實(shí)際實(shí)現(xiàn)當(dāng)中,LifecycleOwner 作為抽象層并不具體負(fù)責(zé)訂閱 LiveData,而是由業(yè)務(wù)層在 LifecycleOwner 中完成具體的訂閱工作,此時(shí)我們稱 LifecycleOwner 為 Controller 更合適,雖然它們往往是同一個東西:

lifecycleowner_observe_livedata

注意圖示,一個 User-defined Observer 必須和一個 LifecycleOwner 唯一綁定,否則將無法訂閱。試想,如果一個 Observer 同時(shí)綁定兩個 LifecycleOwner:L1 和 L2,假如 L1 處于 RESUMED 的狀態(tài),而 L2 處于 DESTROYED 的狀態(tài),那么 LiveData 將無所適從:如果遵循 L1 的狀態(tài),將變化通知給 Observer,則更新 L2 會出錯;如果遵循 L2 的狀態(tài),不將變化通知給 Observer,則 L1 得不到及時(shí)更新。

2.3 多對多的雙向訂閱網(wǎng)

LiveData 和 LifecycleOwner 之間因?yàn)樾枰嗷ビ^察對方狀態(tài)的變化,從而需要實(shí)現(xiàn)雙向訂閱;同時(shí),為了支持良好的可擴(kuò)展能力,各自都維護(hù)了一個觀察者列表,形成一個多對多的雙向訂閱網(wǎng)絡(luò):

bidirection_subscribes

我們看到一個 LiveData 是可以同時(shí)向多個 LifecycleOwner 發(fā)起訂閱的,所以,LiveData 本身其實(shí)并不實(shí)際維護(hù)一個激活狀態(tài),真正的激活狀態(tài)維護(hù)在 LifecycleOwner 的 User-defined observer 中。

3 LiveData 的事件變化

LiveData 值更新之后的需要通知訂閱者(觀察者),其通知流程非常簡單:

livedata_setvalue

其中,判斷觀察者是否激活,即判斷 LifecycleOwner 是否處于 STARTED 或 RESUMED 狀態(tài),在 2.1 節(jié)中已有說明。

我們看一下關(guān)鍵的源代碼:

// 入口
@MainThread
protected void setValue(T value) {
    // 必須在主線程調(diào)用
    assertMainThread("setValue");

    //..省略非關(guān)鍵代碼

    // 設(shè)置新值并派發(fā)通知
    mData = value;
    dispatchingValue(null);
}

// 通知派發(fā)流程
void dispatchingValue(@Nullable ObserverWrapper initiator) {
    //..省略非關(guān)鍵代碼

    // 遍歷觀察者列表
    for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
            mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
        // 嘗試通知觀察者
        considerNotify(iterator.next().getValue());

        //..省略非關(guān)鍵代碼
    }
}

其中 LiveData.considerNotify() 在 2.1 節(jié)中已有說明。

4 LifecycleOwner 的事件變化

對于 LifecycleOwner 來說,其變化的事件即為生命周期狀態(tài)的變化。在 LifecycleOwner 的事件委托者 Lifecycle 看來,無論是發(fā)生了 ON_CREATE 事件還是 ON_START 事件,或是任何其它的事件,其事件的切換流程都是通用的。

換言之,只要 Lifecycle 接口的實(shí)現(xiàn)者實(shí)現(xiàn)這一通用切換流程,便只需給 LifecycleOwner 暴露一個切換入口,就能在 LifecycleOwner 的各個生命周期回調(diào)函數(shù)中調(diào)用這個入口就可以了。這樣我們在 LifecycleOwner 中應(yīng)該可以看到形如這樣的流程(偽代碼表示):

public class Activity/Fragment implements LifecycleOwner {
    @Override
    public onCrate() {
        //...省略非關(guān)鍵代碼

        // 在 Jetpack 框架中,LifecycleImpl 被命名為 LifecycleRegistry
        LifecycleImpl.handleLifecycleEvent(ON_CREATE);
    }

    @Override
    public onStart() {
        //...省略非關(guān)鍵代碼
        LifecycleImpl.handleLifecycleEvent(ON_START);
    }

    @Override
    public onResume() {
        //...省略非關(guān)鍵代碼
        LifecycleImpl.handleLifecycleEvent(ON_RESUME);
    }

    @Override
    public onPause() {
        //...省略非關(guān)鍵代碼
        LifecycleImpl.handleLifecycleEvent(ON_PAUSE);
    }

    @Override
    public onDestroy() {
        //...省略非關(guān)鍵代碼
        LifecycleImpl.handleLifecycleEvent(ON_DESTROY);
    }
}

當(dāng)然,在具體的源代碼中,與上述偽代碼會有一些出入,但是大體的結(jié)構(gòu)是一致的。在 Jetpack 框架中,這個 Lifecycle 的實(shí)現(xiàn)者叫做 LifecycleRegistry。所以我們這里重點(diǎn)需要關(guān)注的就是 LifecycleRegistry 這個 Lifecycle 的代理接口的實(shí)現(xiàn)類是如何通知生命周期事件變化的。

4.1 Lifecycle 接口的實(shí)現(xiàn)——LifecycleRegistry

4.1.1 LifecycleRegistry 的訂閱實(shí)現(xiàn)

如 2.2 節(jié)所述,通過 LiveData.observe(owner, user-defined observer),LifecycleOwner 的業(yè)務(wù)層向 LiveData 訂閱數(shù)據(jù)變化,而在 LiveData.observe() 方法內(nèi),同時(shí)會自動通過 Lifecycle.addObserver(LiveData-defined observer) 向 LifecycleOwner 訂閱生命周期變化:

// LiveData.observe()
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {

    //...省略非關(guān)鍵代碼

    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);

    //...省略非關(guān)鍵代碼

    // 向 LifecycleOwner 發(fā)起訂閱
    owner.getLifecycle().addObserver(wrapper);
}

以上方法內(nèi)的 owner.getLifecycle() 的實(shí)際對象即為 LifecycleRegistry,我們來看一下 LifecycleRegistry.addObserver() 的基本訂閱流程:

lifecycleregistry_addobserver.png

從整個流程來看,總體可以分為三步:

  • 第一步是初始化觀察者對象的狀態(tài),并將觀察者緩存入隊(duì);
  • 第二步是以模擬派發(fā)生命周期事件的形式,將新加入的觀察者的狀態(tài)提升到目前為止可提升的最大狀態(tài);
  • 第三步是同步所有觀察者的狀態(tài)到全局狀態(tài)。

我們可以看到,最后所有的觀察者的狀態(tài)都要同步到全局狀態(tài),全局狀態(tài)即為 LifecyclerOwner 最新的狀態(tài)。那么為什么需要進(jìn)行這么繁瑣的逐步模擬派發(fā)事件來進(jìn)行同步呢?直接一步到位不行么?

我們可以考慮一個生命周期感知組件 LifeLocation,其功能是用于進(jìn)行定位,它訂閱了 LifecycleOwner,我們假設(shè) LifeLocation 需要在 CREATED 的時(shí)候進(jìn)行一些必要的初始化,而在 STARTED 的時(shí)候開始執(zhí)行定位操作。假如在 LifecycleRegistry 中的狀態(tài)同步可以一步同步到全局狀態(tài),那么有可能當(dāng)前的全局狀態(tài)已經(jīng)是 RESUMED 的了,這樣 LifeLocation 既得不到初始化,也無從啟用定位功能了。

所以,以上這種看似繁瑣的模擬派發(fā)狀態(tài)事件的步驟是完全必要的,它讓用戶自定義的生命周期感知組件的狀態(tài)切換流程是可預(yù)測的。

4.1.2 LifecycleRegistry 中的事件流

我們在 4.1.1 節(jié)中的流程圖的第 6 步中提到,要根據(jù) observer.state 來計(jì)算下一個狀態(tài)事件,也就是說按照事件的流向,根據(jù)當(dāng)前的狀態(tài),下一個要發(fā)生的事件是什么。我們修改一下 1.2 節(jié)的時(shí)序圖如下:

lifecycleregistry_event_flow

觀察到圖中左邊的藍(lán)色箭頭,舉個例子,假如當(dāng)前的狀態(tài)是 CREATED,那么接下來要發(fā)生的事件應(yīng)該是 ON_START。藍(lán)色箭頭指示的事件流方向是生命周期由無到生的過程,我們稱為 upEvent 流;與此對應(yīng),右邊的紅色箭頭指示的事件流方向是生命周期由生到死的過程,我們稱之為 downEvent。

4.1.1 節(jié)中的流程圖的第 6 步中正好需要進(jìn)行 upEvent 流操作。除此以外,我們在第 7 步同步到全局狀態(tài)時(shí),還需要用到 upEvent 和 downEvent 流操作,且在 LifecycleOwner 的每一次生命周期的變化中,都需要進(jìn)行上述第 7 步的狀態(tài)同步操作。接下來我們就看一看,當(dāng) LifecycleOwner 生命周期變化后,發(fā)生了什么。

4.1.3 處理生命周期的變化

在 4 節(jié)開頭我們描述了 LifecycleImpl.handleLifecycleEvent() 方法,在 LifecycleRegistry 中也有一個同名的方法,其功能就是處理 LifecycleOwner 生命周期的變化。handleLifecycleEvent() 的處理過程是這樣的:

handlelifecycleevent

如圖所示:

  • Sync 標(biāo)記的部分是進(jìn)行狀態(tài)同步的核心流程,同時(shí)也是 4.1.1 節(jié)流程圖中的第 7 步的具體實(shí)現(xiàn);
  • 每一次生命周期的變化有可能是從無到生的 up 變化,也有可能是從生到死的 down 變化;
  • 如果是 up 變化,則需要進(jìn)行 upEvent 流處理,如果是 down 變化,則需要進(jìn)行 downEvent 流處理;
  • 根據(jù) 4.1.1 節(jié)的描述,我們可以得出,在觀察者隊(duì)列中的所有觀察者,從最老(最開始)到最新(最末),必定維持一個不變性質(zhì):非降序排列;
  • 所以當(dāng) STATE < eldestState 時(shí),說明觀察者隊(duì)列中的所有觀察者狀態(tài)都大于全局狀態(tài),這時(shí)候說明生命周期變化順序是 down 方向的,需要進(jìn)行 downEvent 流處理;
  • 而當(dāng) STATE > newestState 時(shí),說明觀察者隊(duì)列中的所有觀察者狀態(tài)都小于全局狀態(tài),這時(shí)候說明生命周期變化順序是 up 方向的,需要進(jìn)行 upEvent 流處理;
  • 無論是 downEvent 流還是 upEvent 流,都會逐步派發(fā)生命周期事件給各個觀察者。

關(guān)于 downEvent 流和 upEvent 流,我畫了一張更加形象的圖用以加深理解:

downevent_and_upevent

至此,整個 LiveData 和 Lifecycle 的原理就介紹完成了。

5. 關(guān)于觀察者模式的一點(diǎn)思考

不難看出,LiveData 和 Lifecycle 的核心是觀察者模式。無論是 LiveData 還是 Lifecycle,它們的共同點(diǎn)就是都需要維護(hù)一個穩(wěn)定的狀態(tài)機(jī):

  • LiveData 的狀態(tài)機(jī)就是數(shù)據(jù)值的變化,每個值就是一個狀態(tài),理論上可以是一個無限狀態(tài)機(jī);
  • Lifecycle 的狀態(tài)機(jī)就是生命周期的變化,每個生命周期階段就是一個狀態(tài),它是一個有限狀態(tài)機(jī)。

在涉及到狀態(tài)機(jī)模型時(shí),如果我們需要感知狀態(tài)機(jī)當(dāng)前的狀態(tài),一般有兩種方式:主動詢問和被動通知。在復(fù)雜的業(yè)務(wù)中,主動詢問狀態(tài)機(jī)往往是不好的實(shí)踐;而被動通知,可以讓我們的業(yè)務(wù)按照狀態(tài)進(jìn)行清晰的分段,更易于模塊化和測試。觀察者模式就是一種很好的被動通知模式。

所以,當(dāng)我們的對象維護(hù)了一個狀態(tài)機(jī)的時(shí)候,可以考慮是否可以采用觀察者模式來讀取狀態(tài)。但是需要注意的是,觀察者模式內(nèi)部是維護(hù)了一個觀察者引用的列表的,當(dāng)狀態(tài)發(fā)生變化的時(shí)候,是采用順序遍歷的方式逐個進(jìn)行通知的,可以想到,當(dāng)一個被觀察者中維護(hù)的觀察者數(shù)量很多,其中又有很多觀察者對狀態(tài)的響應(yīng)處理都比較耗時(shí)的話,會出現(xiàn)性能瓶頸。尤其是在基于單線程的 UI 環(huán)境下,更加需要引起注意,我們通常應(yīng)該有一個機(jī)制來移除不再需要的觀察者,以減輕通知負(fù)載。

說明:

該文檔參考的 androidx 版本為

core: 1.1.0

lifecyle: 2.2.0-alpha01

fragment: 1.1.0-alpha09

到此這篇關(guān)于Android mvvm之LiveData原理案例詳解的文章就介紹到這了,更多相關(guān)Android mvvm之LiveData原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論