深入理解JetPack之LiveData

LiveData是什么?

1.首先LiveData在用法上其實(shí)是與數(shù)據(jù)實(shí)體類是一樣的東西,它負(fù)責(zé)暫存數(shù)據(jù)。
2.其次LiveData其實(shí)也是一個觀察者模式的數(shù)據(jù)實(shí)體類,它可以跟它注冊的觀察者回調(diào)數(shù)據(jù)是否已經(jīng)更新,比如以前的接口回調(diào)通知可以用LiveData做到。
3.LiveData還能知曉它綁定的Activity或者Fragment的生命周期,它只會給前臺活動的組件回調(diào),避免組件銷毀后發(fā)生意想不到的崩潰情況。

那LiveData是如何做到以上這些功能的呢?

LiveData如何是如何能觀察到組件生命周期的
從使用開始入手源碼:
var myLiveData = MutableLiveData<Any>()

myLiveData.observe(this, Observer {

})

這里通過調(diào)用LiveData的observe()方法來注冊觀察者,LiveData的observe()方法如下:

    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        //該方法調(diào)用者必須在主線程
        assertMainThread("observe");
        //如果處在DESTROYED 狀態(tài),則沒必要添加觀察者
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
       //將包裝結(jié)果添加到Map里
        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);
    }

方法的第一個參數(shù)owner,就是注冊時的組件,即為activity或fragment,需要為實(shí)現(xiàn)LifecycleOwner接口。獲取組件當(dāng)前的生命周期狀態(tài),如果狀態(tài)為DESTROYED,那么直接return,這就保證了DESTROYED狀態(tài)的組件是不允許注冊的。

mObservers.putIfAbsent(observer, wrapper)方法將observer和LifecycleBoundObserver存儲到SafeIterableMap類型的mObservers中,putIfAbsent方法和put方法有區(qū)別,如果傳入key對應(yīng)的value已經(jīng)存在,就返回存在的value,不進(jìn)行替換。如果不存在,就添加key和value,返回null。

最后的owner.getLifecycle().addObserver(wrapper),就在LiveData內(nèi)部完成了Lifecycle的觀察者的添加,這樣LiveData就有了觀察組件生命周期變化的能力。

LiveData是如何回調(diào)observe方法的

    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);
                return;
            }
            activeStateChanged(shouldBeActive());
        }

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

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

當(dāng)宿主(Activity/Fragment) 生命周期發(fā)生改變時會調(diào)用onStateChanged()方法,并且判斷了當(dāng)組件處于DESTROYED狀態(tài)時,會調(diào)用removeObserver方法,來移除observer。所以當(dāng)組件銷毀時,注冊的生命周周觀察者不會再接收到通知,因?yàn)橐呀?jīng)解綁了。

shouldBeActive()用來判斷當(dāng)前宿主是否是活躍狀態(tài),此處定義的活躍狀態(tài)為:宿主的狀態(tài)要>="STARTED"狀態(tài),而該狀態(tài)區(qū)間為:Activity.onStart() 之后且Activity.onPause()之前。
當(dāng)宿主處于活躍狀態(tài)時,才會繼續(xù)通知UI 數(shù)據(jù)變更了,進(jìn)而刷新UI,若是處于非活躍狀態(tài),比如App 失去焦點(diǎn)(onPause()被調(diào)用),那么將不會刷新UI 。

通知觀察者
  • Observer的回調(diào)事件通過setValue和postValue觸發(fā)。

setValue方法:

   @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

從代碼中方法注解可以看出,setValue方法必須運(yùn)行在主線程中,其內(nèi)部調(diào)用了dispatchingValue方法,其后將事件通知回調(diào)給observers。

再看dispatchingValue方法:

    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
                //遍歷調(diào)用所有觀察者
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

在分發(fā)有效的前提下,遍歷mObservers,一次調(diào)用considerNotify()方法。

    private void considerNotify(ObserverWrapper observer) {
//非活躍狀態(tài),直接返回
        if (!observer.mActive) {
            return;
        }
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
       //如果LiveData數(shù)據(jù)版本<= 觀察者的數(shù)據(jù)版本,則直接返回
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //noinspection unchecked
        observer.mObserver.onChanged((T) mData);
    }

如果當(dāng)前observer的mActive值不為true,就直接return。如果判斷條件都滿足,則調(diào)用Observer接口的onChanged()方法,這個方法正是開頭myLiveData.observe(this, Observer {}) Observer接口的方法,因此完成liveData變化對observer回調(diào)事件的輪回。

public interface Observer<T> {
    /**
     * Called when the data is changed.
     * @param t  The new data
     */
    void onChanged(T t);
}
postValue()
     protected void postValue(T value) {
        boolean postTask;
        //子線程、主線程都需要修改mPendingData,因此需要加鎖
        synchronized (mDataLock) {
            //mPendingData 是否還在排隊(duì)等待發(fā)送出去
            //mPendingData == NOT_SET 表示當(dāng)前沒有排隊(duì)
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            //說明上次的Runnable 還沒執(zhí)行
            //直接返回,不需要切換到主線程執(zhí)行
            return;
        }
        //切換到主線程執(zhí)行Runnable
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

    private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            //noinspection unchecked
          // 切換到主線程執(zhí)行Runnable
            setValue((T) newValue);
        }
    };

而postValue方法里,通過任務(wù)(Runnable)的方式在主線程中更新數(shù)據(jù)。而getValue中,如果livedata中mData設(shè)過值就返回mData,否則會返回null,這里在實(shí)際使用中可能會造成空指針異常。

livedata為什么連續(xù)post會丟失數(shù)據(jù)?

我們實(shí)際場景更多的是在子線程發(fā)起的,所以會用postValue來通知數(shù)據(jù)變化。
postValue里首先好會將分發(fā)的值賦值給mPendingData全局變量,然后將值的分發(fā)操作放在一個Runnable里進(jìn)行,從postValue到 ArchTaskExecutor執(zhí)行postToMainThread方法(其實(shí)里面就是mMainHandler.post(runnable))是有一個時間間隙的。
在這個時間間隙中,由于連續(xù)兩次postValue,所以mPendingData帶著第二次的最新值,進(jìn)行分發(fā),所以UI刷新,只能看到第二次的值。
其實(shí)剛才分析過程中我們也看到了,由于第二次執(zhí)行postValue的時候,mPendingData已經(jīng)不是初始值,所以導(dǎo)致postTask為false,在3處,執(zhí)行了return。所以雖然執(zhí)行了兩次postValue,可是ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable)只會執(zhí)行一次。

總結(jié)一下LiveData運(yùn)行流程:

1.通過調(diào)用LiveData的observe()方法來注冊觀察者,獲取組件當(dāng)前的生命周期狀態(tài),如果狀態(tài)為DESTROYED,那么直接return。owner.getLifecycle().addObserver(wrapper),就在LiveData內(nèi)部完成了Lifecycle的觀察者的添加,這樣LiveData就有了觀察組件生命周期變化的能力。

2.當(dāng)組件狀態(tài)發(fā)生變化時,會調(diào)用onStateChanged方法,并且判斷了當(dāng)組件處于DESTROYED狀態(tài)時,會調(diào)用removeObserver方法來移除observer。具體事件分發(fā)是通過ObserverWrapper,它是Observer的包裝類,如果是Active狀態(tài),會調(diào)用dispatchingValue方法,并將自身傳進(jìn)去。

3.在分發(fā)有效的前提下,遍歷mObservers,如果當(dāng)前observer的mActive值不為true,就直接return。如果判斷條件都滿足,則調(diào)用Observer接口的onChanged()方法。

4.最后,通過setValue和postValue方法內(nèi)部調(diào)用dispatchingValue方法,其后將事件通知回調(diào)給observers。

粘性事件

LiveData數(shù)據(jù)變更發(fā)生后,才注冊的觀察者,此時觀察者還能收到變更通知。

這和LiveData 的實(shí)現(xiàn)有關(guān),看看核心源碼實(shí)現(xiàn):

 private void considerNotify(LiveData.ObserverWrapper observer) {
        //mVersion 為LiveData 當(dāng)前數(shù)據(jù)版本,當(dāng)setValue/postValue 發(fā)生時,mVersion++
        //通過比對LiveData 當(dāng)前數(shù)據(jù)版本與觀察者的數(shù)據(jù)版本,若是發(fā)現(xiàn)LiveData 當(dāng)前數(shù)據(jù)版本 更大
        //說明是之前沒有通知過觀察者,因此需要通知,反之則不通知。
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        //將觀察者數(shù)據(jù)版本保持與LiveData 版本一致,表明該觀察者消費(fèi)了最新的數(shù)據(jù)。
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }

再回溯一下流程:

1、初始時LiveData.mVersion= -1,ObserverWrapper.mLastVersion = -1,因此初次進(jìn)入Activity時沒有數(shù)據(jù)通知。
2、當(dāng)點(diǎn)擊按鈕后(LiveData.setValue()),此時LiveData.mVersion = 0;因?yàn)長iveData.mVersion>ObserverWrapper.mLastVersion,因此觀察者能夠收到通知。
3、當(dāng)退出Activity 再進(jìn)來后,因?yàn)镺bserverWrapper 是全新new 出來的,ObserverWrapper.mLastVersion = -1,而LiveData.mVersion =0,還是大于 ObserverWrapper.mLastVersion,因此依然能夠收到通知。

參考:
https://blog.csdn.net/jwg1988/article/details/122925810
https://juejin.cn/post/7081841015643963406

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容