Jetpack入門到精通(五)一文帶你了解LiveData(原理篇)

前言

在上一篇文章中我們學(xué)習(xí)了LiveData的基本用法,我們知道LiveData是一個可觀察的數(shù)據(jù)持有者振诬,他是具有組件生命周期感知的,那么它是如何觀察組件生命周期變化的呢?LiveData和RxJava的不同的是傀蓉,LiveData并不是通知所有觀察者,它只會通知處于Active狀態(tài)的觀察者职抡,如果一個觀察者處于DESTROYED狀態(tài)葬燎,它將不會收到通知,這一點(diǎn)又是如何做到的缚甩?還有另外一點(diǎn)谱净,Transformations的map方法其內(nèi)部進(jìn)行了什么操作?等等問題擅威,會在這篇文章中給大家進(jìn)行講解壕探。

1.LiveData如何觀察組件生命周期變化

通過調(diào)用LiveData的observe方法來注冊觀察者,LiveData的observe方法如下所示郊丛。 frameworks/support/lifecycle/livedata-core/src/main/java/androidx/lifecycle/LiveData.java

 @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        //如果被觀察者的當(dāng)前的狀態(tài)是DESTROYED李请,就return
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {//1
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);//2
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);//3
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        owner.getLifecycle().addObserver(wrapper);//4
    }
復(fù)制代碼

注釋1處的owner實際上就是注冊時傳進(jìn)來來組件,比如Activity厉熟,獲取組件當(dāng)前的狀態(tài)导盅,如果狀態(tài)為DESTROYED,那么直接return庆猫,這說明DESTROYED狀態(tài)的組件是不允許注冊的认轨。

如果你還不了解Lifecycle的狀態(tài),可以查看Android Jetpack架構(gòu)組件(三)帶你了解Lifecycle(原理篇)這篇文章月培。 注釋2處新建了一個LifecycleBoundObserver包裝類嘁字,將owner和observer傳了進(jìn)去。 注釋3處將observer和LifecycleBoundObserver存儲到SafeIterableMap<Observer<? super T>, ObserverWrapper>mObservers中杉畜,putIfAbsent方法和put方法有區(qū)別纪蜒,如果傳入key對應(yīng)的value已經(jīng)存在,就返回存在的value此叠,不進(jìn)行替換纯续。如果不存在,就添加key和value,返回null猬错。 如果等于null窗看,在注釋4處會將LifecycleBoundObserver添加到Lifecycle中完成注冊,這樣當(dāng)我們調(diào)用LiveData的observe方法時倦炒,實際上是LiveData內(nèi)部完成了Lifecycle的觀察者的添加显沈,這樣LiveData自然也就有了觀察組件生命周期變化的能力。

2.LiveData的observe方法回調(diào)

LifecycleBoundObservers是LiveData的內(nèi)部類逢唤,代碼如下所示拉讯。 frameworks/support/lifecycle/livedata-core/src/main/java/androidx/lifecycle/LiveData.java

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

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

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

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

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

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

復(fù)制代碼

LifecycleBoundObserver繼承了ObserverWrapper類,重寫了shouldBeActive方法鳖藕,用于判斷當(dāng)前傳入的組件的狀態(tài)是否是Active的魔慷,Active狀態(tài)包括STARTED和RESUMED狀態(tài)。

LifecycleBoundObserver實現(xiàn)了GenericLifecycleObserver接口著恩,當(dāng)組件狀態(tài)發(fā)生變化時院尔,會調(diào)用onStateChanged方法,當(dāng)組件處于DESTROYED狀態(tài)時页滚,會調(diào)用注釋1處的removeObserver方法召边,來移除observer。 這樣在文章開頭的疑問就解決了裹驰,為什么一個觀察者(組件)處于DESTROYED狀態(tài)時隧熙,它將不會收到通知。

接著會調(diào)用注釋2處的activeStateChange方法幻林,代碼如下所示贞盯。

frameworks/support/lifecycle/livedata-core/src/main/java/androidx/lifecycle/LiveData.java

  private abstract class ObserverWrapper {
        final Observer<? super T> mObserver;
        boolean mActive;
        int mLastVersion = START_VERSION;

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

        abstract boolean shouldBeActive();

        boolean isAttachedTo(LifecycleOwner owner) {
            return false;
        }

        void detachObserver() {
        }

        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            if (wasInactive && mActive) {
                onActive();
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive();
            }
            if (mActive) {
                dispatchingValue(this);//1
            }
        }
    }
復(fù)制代碼

activeStateChanged方法定義在抽象類ObserverWrapper中,它是Observer的包裝類沪饺,activeStateChanged方法會根據(jù)Active狀態(tài)和處于Active狀態(tài)的組件的數(shù)量躏敢,來對onActive方法和onInactive方法回調(diào),這兩個方法用于拓展LiveData對象整葡。注釋1處件余,如果是Active狀態(tài),會調(diào)用dispatchingValue方法遭居,并將自身傳進(jìn)去啼器。

  private void dispatchingValue(@Nullable ObserverWrapper initiator) {
        //正在處于分發(fā)狀態(tài)中
        if (mDispatchingValue) {
            //分發(fā)無效
            mDispatchInvalidated = true;//1
            return;
        }
        mDispatchingValue = true;
        do {
            //分發(fā)有效
            mDispatchInvalidated = false;
            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());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        //標(biāo)記不處于分發(fā)狀態(tài)
        mDispatchingValue = false;
    }
復(fù)制代碼

mDispatchingValue用于標(biāo)記當(dāng)前是否處于分發(fā)狀態(tài)中,如果處于該狀態(tài)俱萍,則在注釋1處標(biāo)記當(dāng)前分發(fā)無效端壳,直接return。一路調(diào)用過來枪蘑,ObserverWrapper是不為null的损谦,ObserverWrapper為null的情況第3小節(jié)會講到岖免,無論是那種情況,都會調(diào)用considerNotify方法照捡,代碼如下所示颅湘。

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

復(fù)制代碼

considerNotify方法中做了多次的判斷,注釋1處栗精,如果ObserverWrapper的mActive值不為true栅炒,就直接return。注釋2處术羔,如果當(dāng)前observer對應(yīng)組件的狀態(tài)不是Active,就會再次調(diào)用activeStateChanged方法乙漓,并傳入false级历,其方法內(nèi)部會再次判斷是否執(zhí)行onActive方法和onInactive方法回調(diào)。如果判斷條件都滿足會調(diào)用Observer的onChanged方法叭披,這個方法正是使用LiveData的observe方法的回調(diào)寥殖。

3.postValue/setValue方法分析

當(dāng)調(diào)用MutableLiveData的observe方法后,還需要通過postValue/setValue方法來更新數(shù)據(jù)涩蜘。 frameworks/support/lifecycle/livedata-core/src/main/java/androidx/lifecycle/LiveData.java

...
  private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            //noinspection unchecked
            setValue((T) newValue);//1
        }
    };
    ...
    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);//2
    }

    @MainThread //3
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }
復(fù)制代碼

postValue/setValue方法都定義在LiveData中嚼贡,根據(jù)注釋1和注釋2處,可以發(fā)現(xiàn)postValue方法實際上就是將setValue方法切換到主線程調(diào)用同诫。注釋3處說明setValue方法是運(yùn)行在主線程中的粤策,其內(nèi)部調(diào)用了dispatchingValue方法,這個方法在第2小節(jié)介紹過误窖,也就是dispatchingValue方法的參數(shù)ObserverWrapper為null的情況叮盘。 從這里我們可以知道,無論是LiveData的observe方法還是LiveData的postValue/setValue方法都會調(diào)用dispatchingValue方法霹俺。

4.Transformations.map方法分析

除了以上講的常用的方法之外柔吼,還可能會使用到Transformations.map和Transformations.switchMap方法,這里以Transformations.map為例丙唧。這個方法用來在LiveData對象分發(fā)給觀察者之前對其中存儲的值進(jìn)行更改愈魏, 代碼如下所示。 frameworks/support/lifecycle/livedata/src/main/java/androidx/lifecycle/Transformations.java

@MainThread
    public static <X, Y> LiveData<Y> map(
            @NonNull LiveData<X> source,
            @NonNull final Function<X, Y> mapFunction) {
        final MediatorLiveData<Y> result = new MediatorLiveData<>();//1
        result.addSource(source, new Observer<X>() {
            @Override
            public void onChanged(@Nullable X x) {
                result.setValue(mapFunction.apply(x));
            }
        });
        return result;
    }
復(fù)制代碼

Transformations.map方法運(yùn)行在主線程想际,注釋1處創(chuàng)建了MediatorLiveData培漏,緊接著調(diào)用了它的addSource方法: support/lifecycle/livedata/src/main/java/androidx/lifecycle/MediatorLiveData.java

  */
    @MainThread
    public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
        Source<S> e = new Source<>(source, onChanged);//1
        Source<?> existing = mSources.putIfAbsent(source, e);
        if (existing != null && existing.mObserver != onChanged) {
            throw new IllegalArgumentException(
                    "This source was already added with the different observer");
        }
        if (existing != null) {
            return;
        }
        if (hasActiveObservers()) {
            e.plug();//2
        }
    }
復(fù)制代碼

注釋1處將傳進(jìn)來的LiveData和onChanged封裝到Source類中,注釋2處調(diào)用了Source的plug方法:

 private static class Source<V> implements Observer<V> {
        final LiveData<V> mLiveData;
        final Observer<? super V> mObserver;
        int mVersion = START_VERSION;

        Source(LiveData<V> liveData, final Observer<? super V> observer) {
            mLiveData = liveData;
            mObserver = observer;
        }

        void plug() {
            mLiveData.observeForever(this);//1
        }

        void unplug() {
            mLiveData.removeObserver(this);
        }

        @Override
        public void onChanged(@Nullable V v) {
            if (mVersion != mLiveData.getVersion()) {
                mVersion = mLiveData.getVersion();
                mObserver.onChanged(v);//2
            }
        }
    }
復(fù)制代碼

注釋2處可以看到沼琉,Transformations.map方法傳入的Observer的回調(diào)在這里進(jìn)行處理北苟。注釋1處,Source的plug方法會調(diào)用LiveData的observeForever方法打瘪,這個和第2小節(jié)所講的內(nèi)容有什么區(qū)別呢友鼻?我們再往下看傻昙。 frameworks/support/lifecycle/livedata-core/src/main/java/androidx/lifecycle/LiveData.java

    @MainThread
    public void observeForever(@NonNull Observer<? super T> observer) {
        assertMainThread("observeForever");
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);//1
        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);
    }

復(fù)制代碼

注釋1處用AlwaysActiveObserver來對Observer進(jìn)行包裝,緊接著調(diào)用AlwaysActiveObserver的activeStateChanged方法彩扔,其內(nèi)部實際調(diào)用的是ObserverWrapper的activeStateChanged方法妆档,這個在第二小節(jié)已經(jīng)做了分析,就不再贅述了虫碉。來看AlwaysActiveObserver類是如何定義的贾惦。 frameworks/support/lifecycle/livedata-core/src/main/java/androidx/lifecycle/LiveData.java

   private class AlwaysActiveObserver extends ObserverWrapper {
        AlwaysActiveObserver(Observer<? super T> observer) {
            super(observer);
        }
        @Override
        boolean shouldBeActive() {
            return true;
        }
    }
復(fù)制代碼

AlwaysActiveObserver是LiveData的內(nèi)部類,它繼承自O(shè)bserverWrapper敦捧,AlwaysActiveObserver是LiveData的內(nèi)部類和ObserverWrapper的區(qū)別就是须板,它是永遠(yuǎn)處于Active狀態(tài)的。

5.LiveData關(guān)聯(lián)類

接下來給出LiveData關(guān)聯(lián)類的UML圖兢卵,看明白這個圖以后习瑰,再回去重新閱讀本文,也許你會收獲更多秽荤。

可以看到甜奄,在講解LiveData時涉及的大部分類都在這個圖中,其中MutableLiveData繼承自LiveData窃款,LifecycleOwner和Observer和LiveData有關(guān)聯(lián)的關(guān)系课兄,ObserverWrapper是Observer的包裝類,因此它們有著關(guān)聯(lián)的關(guān)系晨继,其他的類大家看圖就知道了烟阐。

本文在開源項目:https://github.com/Android-Alvin/Android-LearningNotes 中已收錄,里面包含不同方向的自學(xué)編程路線踱稍、面試題集合/面經(jīng)曲饱、及系列技術(shù)文章等,資源持續(xù)更新中...

作者:劉望舒
鏈接:https://juejin.cn/post/6844903982691794952
來源:掘金
著作權(quán)歸作者所有珠月。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)扩淀,非商業(yè)轉(zhuǎn)載請注明出處。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末啤挎,一起剝皮案震驚了整個濱河市驻谆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌庆聘,老刑警劉巖胜臊,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異伙判,居然都是意外死亡象对,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門宴抚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來勒魔,“玉大人甫煞,你說我怎么就攤上這事」诰睿” “怎么了抚吠?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長弟胀。 經(jīng)常有香客問我楷力,道長,這世上最難降的妖魔是什么孵户? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任萧朝,我火速辦了婚禮,結(jié)果婚禮上夏哭,老公的妹妹穿的比我還像新娘剪勿。我一直安慰自己,他們只是感情好方庭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著酱固,像睡著了一般械念。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上运悲,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天龄减,我揣著相機(jī)與錄音,去河邊找鬼班眯。 笑死希停,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的署隘。 我是一名探鬼主播宠能,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼磁餐!你這毒婦竟也來了违崇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤诊霹,失蹤者是張志新(化名)和其女友劉穎羞延,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體脾还,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伴箩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了鄙漏。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嗤谚。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡棺蛛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出呵恢,到底是詐尸還是另有隱情鞠值,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布渗钉,位于F島的核電站彤恶,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏鳄橘。R本人自食惡果不足惜声离,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瘫怜。 院中可真熱鬧术徊,春花似錦、人聲如沸鲸湃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽暗挑。三九已至笋除,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間炸裆,已是汗流浹背垃它。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留烹看,地道東北人国拇。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像惯殊,于是被迫代替她去往敵國和親酱吝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

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