LiveData 源碼解析

LiveData 源碼解析

之前做過一篇關(guān)于Lifecycle的源碼解析,里面分析了

  1. 生命周期擁有者如何進行生命周期的感知(通過Fragment)
  2. 當生命周期變化時,如何進行進行通知:將Obsever進行包裝,生成LifecycleEventObserver的具體實現(xiàn)來,然后在生命周期變化時,調(diào)用其對應的狀態(tài)的分發(fā)。

在通常進行使用的過程中,我們都是將數(shù)據(jù)通過 LiveData 進行一層包裝,然后就可以進行其數(shù)據(jù)的變化監(jiān)聽了,那么其具體是如何實現(xiàn)的呢?

慣例,先來個簡單的測試demo

object SplashViewModel{
    var logined = MutableLiveData<Boolean>()
    init {
        logined.postValue(true)
    }
}

class SplashActivity : BaseBindingActivity<ActivitySplashBinding, SplashViewModel>() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        SplashViewModel.logined.observe(this, Observer { print(it)})
    }
}

只需要一個簡單的 observe() 方法,就可以實現(xiàn)生命周期的監(jiān)聽,然后將數(shù)據(jù)發(fā)送到我們的Activity中,我們看看這個方法里面到底做了什么

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // 頁面銷毀,直接返回
        return;
    }
    //包裝
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    if (existing != null && !existing.isAttachedTo(owner)) {
        //如果已經(jīng)存在,拋異常
        throw new IllegalArgumentException("Cannot add the same observer with different lifecycles");
    }
    if (existing != null) {
        return;
    }
    //增加一個監(jiān)聽者
    owner.getLifecycle().addObserver(wrapper);
}

可以看到,只是將我們的生命周期擁有者和監(jiān)聽者進行了一次包裝,生成了 LifecycleBoundObserver 類,然后將它添加到監(jiān)聽者列表中。

在之前的Lifecycle的源碼解析文章中,我們了解到,當頁面發(fā)生變化時,會調(diào)用監(jiān)聽者的 onStateChanged() 方法。

        @Override
        boolean shouldBeActive() {//判斷當前頁面是否屬于激活狀態(tài)(即可見狀態(tài))
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                                   @NonNull Lifecycle.Event event) {
            //如果頁面銷毀了,則直接移除當前對應的監(jiān)聽者
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            //進行狀態(tài)的變更
            activeStateChanged(shouldBeActive());
        }

所以當界面的生命周期變化時,會調(diào)用 activeStateChanged() 來進行狀態(tài)的變更處理

        //進行狀態(tài)的轉(zhuǎn)變
        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            //LiveData的激活的觀察者數(shù)量進行變化
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            if (wasInactive && mActive) {
                //原來沒有激活的觀察者,現(xiàn)在有了新增的
                // 說明LiveData從無激活的觀察者->有激活的觀察者
                onActive();//留下鉤子,給繼承者使用
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                //當前頁面未激活,并且變化后,LiveData中處于激活狀態(tài)的觀察者數(shù)量為0,
                // 說明LiveData從有激活的觀察者->無激活的觀察者
                onInactive();//留下鉤子,給繼承者使用
            }
            if (mActive) {//如果頁面變化為了激活狀態(tài),那么進行數(shù)據(jù)的分發(fā)
                dispatchingValue(this);
            }
        }
    }

這里主要根據(jù)頁面的激活數(shù),預留了兩個鉤子函數(shù),用戶可以做一些自己的數(shù)據(jù)處理。最主要的還是 dispatchingValue() 中的數(shù)據(jù)處理。

    //分發(fā)數(shù)據(jù)
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            //如果正在分發(fā),則將mDispatchInvalidated置為true,那么在分發(fā)過程中,會根據(jù)這個標志位重新新數(shù)據(jù)的分發(fā)
            mDispatchInvalidated = true;
            return;
        }
        //標記正在進行數(shù)據(jù)的分發(fā)
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {//如果有對應的監(jiān)聽者,直接分發(fā)給對應的監(jiān)聽者
                considerNotify(initiator);
                initiator = null;
            } else {
                //遍歷所有的觀察者,然后進行數(shù)據(jù)的分發(fā),
                // 如果分發(fā)過程中,發(fā)現(xiàn)mDispatchInvalidated變化了,那么說明有新的數(shù)據(jù)變更,則退出當前混選,然后從新分發(fā)新的數(shù)據(jù)
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                     mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }
    
    //通知某個觀察者進行了數(shù)據(jù)的變化
    private void considerNotify(ObserverWrapper observer) {
        //觀察者未激活,返回
        if (!observer.mActive) {
            return;
        }
        //觀察者當前狀態(tài)為激活,但是當前變?yōu)榱瞬豢梢姞顟B(tài),那么調(diào)用
        //activeStateChanged方法
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        //如果數(shù)據(jù)版本已經(jīng)是最新的了,那么直接返回
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        //修改數(shù)據(jù)版本號
        observer.mLastVersion = mVersion;
        //調(diào)用監(jiān)聽者的onChanged方法
        observer.mObserver.onChanged((T) mData);
    }

在數(shù)據(jù)分發(fā)過程中,根據(jù)相應的觀察者數(shù)據(jù)版本號,然后和當前的數(shù)據(jù)的版本號進行比較,如果是新的數(shù)據(jù),那么調(diào)用觀察者的 onChange()方法,也就是我們在開始時寫的測試demo中的 print(it) 。

總結(jié)一下頁面發(fā)生變化時,數(shù)據(jù)的處理流程:

  1. 當頁面發(fā)生變化,從不可見變?yōu)榭梢姇r,會將LiveData中的數(shù)據(jù)版本號跟對應的觀察者中的版本號進行比較,如果大,則調(diào)用onChanged()進行數(shù)據(jù)的回調(diào)。
  2. 如果頁面為不可見,那么不會進行數(shù)據(jù)的回調(diào)處理。

那么當我們使用 setValue() ,或者 postValue() 時,LiveData 又是做了什么處理呢?

我們先看看 setValue()

    protected void setValue(T value) {
        assertMainThread("setValue");
        //記錄當前數(shù)據(jù)的版本號
        mVersion++;
        //記錄設置的數(shù)據(jù)值
        mData = value;
        //進行數(shù)據(jù)的分發(fā)
        dispatchingValue(null);
    }

可以看到,直接將數(shù)據(jù)版本號+1,然后進行了數(shù)據(jù)的分發(fā),dispatchingValue() 我們剛才進行過分析,如果參數(shù)為null,那么會遍歷所有的監(jiān)聽者,逐個通知所有觀察者進行了數(shù)據(jù)的變化(前提是觀察者處于激活狀態(tài))。

我們再看看 postValue()

     protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        //通過線程池分發(fā)到主線程去處理
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }
    
    private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            setValue((T) newValue);
        }
    };

可以看到, postValue() 通過線程池技術(shù),將數(shù)據(jù)在主線程進行了 setValue()。

匯總

1.當生命周期不可見時,會將最新的數(shù)據(jù)保存在LiveData中,然后保存相應的版本號,當其可見時,會將數(shù)據(jù)變化通知
2.當LiveData中的數(shù)據(jù)變化時,會遍歷所有的監(jiān)聽頁面,然后進行數(shù)據(jù)的變化通知。

附帶一張ObserverWrapper 的結(jié)構(gòu)圖

image-20200304141507165

本文由博客一文多發(fā)平臺 OpenWrite 發(fā)布!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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

  • LiveData是Google發(fā)布的一個架構(gòu)組件,它是一個數(shù)據(jù)持有類,并且數(shù)據(jù)可以被觀察。區(qū)別于普通的被觀察者,L...
    小小的coder閱讀 138評論 0 0
  • LiveData是Google發(fā)布的一個架構(gòu)組件,它是一個數(shù)據(jù)持有類,并且數(shù)據(jù)可以被觀察。區(qū)別于普通的被觀察者,L...
    lxbnjupt閱讀 614評論 0 2
  • LiveData 使用最新的 androidx 的源碼。 前言 LiveData 是 Android Archit...
    ldlywt閱讀 970評論 0 2
  • 掘金文章鏈接 基于:macOs:10.14/AS:3.4/Android build-tools:28.0.0 思...
    冰川孤辰js閱讀 1,580評論 0 2
  • 0.前言 關(guān)于livedata的使用詳情見LiveData+ViewModel+RxJava2+autoDispo...
    雯藝雪閱讀 1,028評論 1 2