JetPack-LiveData源碼解析

LiveData原理分析

使用方法

這里借助谷歌官方文檔來簡單說明LiveData的用法:

    class NameViewModel : ViewModel() {

        // Create a LiveData with a String
        val currentName: MutableLiveData<String> by lazy {
            MutableLiveData<String>()
        }

        // Rest of the ViewModel...
    }
    

創(chuàng)建一個LiveData對象

class NameActivity : AppCompatActivity() {

    // Use the 'by viewModels()' Kotlin property delegate
    // from the activity-ktx artifact
    private val model: NameViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Other code to setup the activity...

        // Create the observer which updates the UI.
        val nameObserver = Observer<String> { newName ->
            // Update the UI, in this case, a TextView.
            nameTextView.text = newName
        }

        // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
        model.currentName.observe(this, nameObserver)

        button.setOnClickListener {
            val anotherName = "John Doe"
            model.currentName.setValue(anotherName)
        }
    }
}

調(diào)用了observe方法后,就已經(jīng)注冊了監(jiān)聽。
后面不需要在onDestroy內(nèi)部移除observer,這一切都在livedata內(nèi)部做好了,非常方便。
下面來看它的邏輯是怎樣實現(xiàn)的


源碼分析

首先,它的內(nèi)部是通過一個Map存儲所有的觀察者
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>();
key是observer,value是包裝類LifecycleBoundObserver。

當調(diào)用observe()方法時,會將其放入mObservers中。

    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        // 1
        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;
        }
        // 2 
        owner.getLifecycle().addObserver(wrapper);
    }

關鍵點如上面
注釋1,先將二者放入map中,便于后面通知所有的觀察者;
注釋2處將當前wrapper再添加進LifeCycle的觀察者中,以便在頁面生命周期變化時,得到通知,這部分后面再具體說明。

通過第一步,觀察者已經(jīng)添加進來了,一共有兩部分:

  • 外面添加的用于觀察數(shù)據(jù)變化的observer
  • LiveData自身向LifeCycle添加的生命周期wrapper observer

下面分別看看它們是怎樣通知數(shù)據(jù)變化的。


數(shù)據(jù)變化的通知

當調(diào)用setValue設置數(shù)據(jù)時,代碼如下:

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

主要是dispatchingValue方法,如果參數(shù)傳入null,則會遍歷通知所有的觀察者,否則只會通知傳入的特定觀察者

    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                // 如果該參數(shù)不是null,那么只會通知這個特定的觀察者
                considerNotify(initiator);
                initiator = null;
            } else {
                // 否則,循環(huán)遍歷mObservers,逐個通知
                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ù)是null,主要看for循環(huán)中的considerNotify方法

    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }

        // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
        //
        // we still first check observer.active to keep it as the entrance for events. So even if
        // the observer moved to an active state, if we've not received that event, we better not
        // notify for a more predictable notification order.
        // 為了萬無一失,再次檢查頁面的狀態(tài)是否已經(jīng)start或resume
        if (!observer.shouldBeActive()) {
            // 如果不是,則重新刷新LiveData內(nèi)部生命周期監(jiān)聽的狀態(tài)
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //noinspection unchecked
        // 回調(diào)onChanged方法,這里就回到我們設置的自定義監(jiān)聽了
        observer.mObserver.onChanged((T) mData);
    }

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

上面的邏輯簡單總結(jié)如下:
由于在LiveData內(nèi)部持有了LifeCycle的生命周期監(jiān)聽,在數(shù)據(jù)發(fā)生變化,要通知外部的時候,先檢查生命周期的狀態(tài),如果已經(jīng)不是在start或resume,則不會發(fā)出通知。否則,就回調(diào)onChanged方法


生命周期變化的監(jiān)聽

在調(diào)用LiveData.observe()方法時,其內(nèi)部同時調(diào)用了LifeCycle.addObserver()方法,傳入的參數(shù)是LiveData的內(nèi)部類LifecycleBoundObserver,它實現(xiàn)了GenericLifecycleObserver接口。

主要看下它的onStateChanged()方法

@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());
}

// 該方法主要在監(jiān)測到頁面銷毀時調(diào)用,移除自身作為lifeCycle的觀察者
void detachObserver() {
    mOwner.getLifecycle().removeObserver(this);
}

可以看到,當觀察到頁面銷毀時,會調(diào)用LiveData.removeObserver去移除當前相關聯(lián)的observer,也就是我們調(diào)用LiveDta.observe()時傳入的自定義數(shù)據(jù)觀察者,避免了內(nèi)存泄露產(chǎn)生。

當不是destroy狀態(tài),而是start或者resume時,則會去調(diào)用activeStateChanged(true),隨后,又會調(diào)用dispatchingValue(this),上文我們講過,當傳入的參數(shù)不是null的時候,只會通知這一條特定的觀察者,這時一條完整的通知邏輯就出現(xiàn)了。
這里使得當應用從后臺切到前臺時,數(shù)據(jù)始終可以保持是最新的狀態(tài)

    public void removeObserver(@NonNull final Observer<? super T> observer) {
        assertMainThread("removeObserver");
        // 先刪除我們傳入的observer
        ObserverWrapper removed = mObservers.remove(observer);
        if (removed == null) {
            return;
        }

        // 再將自身作為lifeCycle觀察者的身份移除
        removed.detachObserver();
        removed.activeStateChanged(false);
    }

關鍵點都在代碼中注釋出來了。
直到將兩個觀察者對象都完全移除,該觀察者的責任就走到了盡頭。


總結(jié)

  • LiveData是黏性監(jiān)聽的。在首次設置監(jiān)聽時,會遍歷所有的觀察者,做一次通知
  • LiveData通過維護2個觀察者,實現(xiàn)了數(shù)據(jù)+生命周期的監(jiān)聽。一個是我們傳入的數(shù)據(jù)Observer,另一個是其自身向LifeCycle設置的生命周期監(jiān)聽
  • LiveData只會去給處于前臺(STARTED和RESUMED) 的頁面發(fā)送數(shù)據(jù)變化通知
  • 不會發(fā)生內(nèi)存泄露:類似的,在監(jiān)測到頁面Destroy時,會同時移除上面兩個監(jiān)聽,避免內(nèi)存泄露
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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