LiveData 源碼解析

LiveData 源碼解析

以前作過一篇關於Lifecycle的源碼解析,裏面分析了app

  1. 生命週期擁有者如何進行生命週期的感知(經過Fragment)
  2. 當生命週期變化時,如何進行進行通知:將Obsever進行包裝,生成LifecycleEventObserver的具體實現來,而後在生命週期變化時,調用其對應的狀態的分發。

在一般進行使用的過程當中,咱們都是將數據經過 LiveData 進行一層包裝,而後就能夠進行其數據的變化監聽了,那麼其具體是如何實現的呢?ide

慣例,先來個簡單的測試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() 方法,就能夠實現生命週期的監聽,而後將數據發送到咱們的Activity中,咱們看看這個方法裏面到底作了什麼post

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)) {
        //若是已經存在,拋異常
        throw new IllegalArgumentException("Cannot add the same observer with different lifecycles");
    }
    if (existing != null) {
        return;
    }
    //增長一個監聽者
    owner.getLifecycle().addObserver(wrapper);
}

能夠看到,只是將咱們的生命週期擁有者和監聽者進行了一次包裝,生成了 LifecycleBoundObserver 類,而後將它添加到監聽者列表中。測試

在以前的Lifecycle的源碼解析文章中,咱們瞭解到,當頁面發生變化時,會調用監聽者的 onStateChanged() 方法。this

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

        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                                   @NonNull Lifecycle.Event event) {
            //若是頁面銷燬了,則直接移除當前對應的監聽者
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            //進行狀態的變動
            activeStateChanged(shouldBeActive());
        }

因此當界面的生命週期變化時,會調用 activeStateChanged() 來進行狀態的變動處理spa

//進行狀態的轉變
        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            //LiveData的激活的觀察者數量進行變化
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            if (wasInactive && mActive) {
                //原來沒有激活的觀察者,如今有了新增的
                // 說明LiveData從無激活的觀察者->有激活的觀察者
                onActive();//留下鉤子,給繼承者使用
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                //當前頁面未激活,而且變化後,LiveData中處於激活狀態的觀察者數量爲0,
                // 說明LiveData從有激活的觀察者->無激活的觀察者
                onInactive();//留下鉤子,給繼承者使用
            }
            if (mActive) {//若是頁面變化爲了激活狀態,那麼進行數據的分發
                dispatchingValue(this);
            }
        }
    }

這裏主要根據頁面的激活數,預留了兩個鉤子函數,用戶能夠作一些本身的數據處理。最主要的仍是 dispatchingValue() 中的數據處理。線程

//分發數據
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            //若是正在分發,則將mDispatchInvalidated置爲true,那麼在分發過程當中,會根據這個標誌位從新新數據的分發
            mDispatchInvalidated = true;
            return;
        }
        //標記正在進行數據的分發
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {//若是有對應的監聽者,直接分發給對應的監聽者
                considerNotify(initiator);
                initiator = null;
            } else {
                //遍歷全部的觀察者,而後進行數據的分發,
                // 若是分發過程當中,發現mDispatchInvalidated變化了,那麼說明有新的數據變動,則退出當前混選,而後重新分發新的數據
                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;
        }
        //觀察者當前狀態爲激活,可是當前變爲了避免可見狀態,那麼調用
        //activeStateChanged方法
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        //若是數據版本已是最新的了,那麼直接返回
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        //修改數據版本號
        observer.mLastVersion = mVersion;
        //調用監聽者的onChanged方法
        observer.mObserver.onChanged((T) mData);
    }

在數據分發過程當中,根據相應的觀察者數據版本號,而後和當前的數據的版本號進行比較,若是是新的數據,那麼調用觀察者的 onChange()方法,也就是咱們在開始時寫的測試demo中的 print(it)code

總結一下頁面發生變化時,數據的處理流程:server

  1. 當頁面發生變化,從不可見變爲可見時,會將LiveData中的數據版本號跟對應的觀察者中的版本號進行比較,若是大,則調用onChanged()進行數據的回調。
  2. 若是頁面爲不可見,那麼不會進行數據的回調處理。

那麼當咱們使用 setValue() ,或者 postValue() 時,LiveData 又是作了什麼處理呢?

咱們先看看 setValue()

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

能夠看到,直接將數據版本號+1,而後進行了數據的分發,dispatchingValue() 咱們剛纔進行過度析,若是參數爲null,那麼會遍歷全部的監聽者,逐個通知全部觀察者進行了數據的變化(前提是觀察者處於激活狀態)。

咱們再看看 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() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            setValue((T) newValue);
        }
    };

能夠看到, postValue() 經過線程池技術,將數據在主線程進行了 setValue()。

彙總

1.當生命週期不可見時,會將最新的數據保存在LiveData中,而後保存相應的版本號,當其可見時,會將數據變化通知
2.當LiveData中的數據變化時,會遍歷全部的監聽頁面,而後進行數據的變化通知。

附帶一張ObserverWrapper 的結構圖

image-20200304141507165

本文由博客一文多發平臺 OpenWrite 發佈!
相關文章
相關標籤/搜索