4. Jetpack源碼解析—LiveData的使用及工作原理

1. 背景

上一篇我們分析了Lifecycles組件的源碼,本篇我們將繼續分析LiveData組件

相關係列文章:

1. Jetpack源碼解析—看完你就知道Navigation是什麼了?

2. Jetpack源碼解析—Navigation爲什麼切換Fragment會重繪?

3. Jetpack源碼解析—用Lifecycles管理生命週期

2. 基礎

2.1 簡介

LiveData是一個可觀察的數據持有者類,與常規observable不同,LiveData是生命週期感知的,這意味着它尊重其他應用程序組件的生命週期,例如ActivityFragmentService。此感知確保LiveData僅更新處於活動生命週期狀態的應用程序組件觀察者。

2.2 優點

1. 確保UI符合數據狀態
LiveData遵循觀察者模式。 當生命週期狀態改變時,LiveData會向Observer發出通知。 您可以把更新UI的代碼合併在這些Observer對象中。不必去考慮導致數據變化的各個時機,每次數據有變化,Observer都會去更新UI。

2. 沒有內存泄漏
Observer會綁定具有生命週期的對象,並在這個綁定的對象被銷燬後自行清理。

3. 不會因停止Activity而發生崩潰
如果Observer的生命週期處於非活躍狀態,例如在後退堆棧中的Activity,就不會收到任何LiveData事件的通知。

4.不需要手動處理生命週期
UI組件只需要去觀察相關數據,不需要手動去停止或恢復觀察。LiveData會進行自動管理這些事情,因爲在觀察時,它會感知到相應組件的生命週期變化。

5. 始終保持最新的數據
如果一個對象的生命週期變到非活躍狀態,它將在再次變爲活躍狀態時接收最新的數據。 例如,後臺Activity在返回到前臺後立即收到最新數據。

6. 正確應對配置更改
如果一個Activity或Fragment由於配置更改(如設備旋轉)而重新創建,它會立即收到最新的可用數據。

7.共享資源
您可以使用單例模式擴展LiveData對象幷包裝成系統服務,以便在應用程序中進行共享。LiveData對象一旦連接到系統服務,任何需要該資源的Observer都只需觀察這個LiveData對象。

2.3 基本使用

在我們的Jetpack_Note中有使用demo,具體可查看LiveDataFragment
Demo中通過對一個LiveData對象進行生命週期的監聽,實現將值打印在控制檯中。首先聲明一個LiveData對象:

private lateinit var liveData: MutableLiveData<String>

點擊開始觀察數據按鈕,彈出控制檯,我們可以看到控制檯輸出了onStart()日誌,因爲我們將liveData的值和Fragment的生命週期進行了綁定,當返回桌面或者銷燬Fragment的時候,LiveData的值會變成相應的生命週期函數,並打印在控制檯中:

class LiveDataFragment : Fragment() {

    private lateinit var liveData: MutableLiveData<String>

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_live_data, container, false)
    }


    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        liveData = MutableLiveData()
        btn_observer_data.setOnClickListener {
            if (FloatWindow.get() == null) {
                FloatWindowUtils.init(activity?.application!!)
            }
            FloatWindowUtils.show()

            //創建一個觀察者去更新UI
            val statusObserver = Observer<String> { lifeStatus ->
                FloatWindowUtils.addViewContent("LiveData-onChanged: $lifeStatus")
            }
            liveData.observeForever(statusObserver)
        }
    }


    override fun onStart() {
        super.onStart()
        liveData.value = "onStart()"
    }


    override fun onPause() {
        super.onPause()
        liveData.value = "onPause()"
    }

    override fun onStop() {
        super.onStop()
        liveData.value = "onStop()"
    }

    override fun onDestroy() {
        super.onDestroy()
        liveData.value = "onDestroy()"
    }
}

**注意:**這裏我使用了observeForever監聽了所有生命週期方法,所以你會看到onDestroy()等生命週期函數的打印。

好了,Demo很簡單,接下來我們來看一下源碼,進行分析:

3. 源碼分析:

3.1 observer()

我們聲明瞭一個LiveData對象,並通過監聽Fragment的生命週期來改變LiveData中的value值,LiveData實際上就像一個容器,Demo中存儲了一個String類型的值,當這個值發生改變的時候,可以在回調中監聽到他的改變。接下來我們就先從addObserver入手:

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

查看源碼,我們調用observer()時,傳遞了兩個參數,第一個是LifecycleOwner接口實例,而我們繼承的Fragment本身就已經實現了這個接口,所以我們傳this即可;第二個參數Observer就是我們觀察的回調。接下來將這兩個參數傳遞new出了一個新的對象:LifecycleBoundObserver,最後將LifecycleBoundObserverLifecycleOwner進行了綁定,其實這裏面我們可以將LifecycleOwner就理解成我們的Fragment或者Activity的實例,因爲它們都實現了LifecycleOwner

3.2 LifecycleBoundObserver

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
        .....
        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }
        //Activity生命週期變化時,回調方法
        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            //更新livedata活躍狀態
            activeStateChanged(shouldBeActive());
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }
        //解除監聽
        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }

我們可以看到這裏面與LifecycleOwner進行了綁定,並且實現了onStateChanged方法,當生命週期發生變化時執行activeStateChanged(shouldBeActive());方法;shouldBeActive() 返回了 要求生命週期至少是STARTED狀態才被認爲是activie狀態;如果state是DESTROYED狀態時,解綁LifecycleOwnerLiveData。接下來我們看下怎樣更新livedata中數據值:

3.3 dispatchingValue()

我們追蹤activeStateChanged方法發現,在裏面做了一些活躍狀態值的操作,並且當狀態活躍時,更新數據值:

void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            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);
            }
        }
void dispatchingValue(@Nullable ObserverWrapper initiator) {
    ...
    //遍歷LiveData的所有觀察者執行下面代碼
    for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
    ...
}
//將數據值回調到livedata.observer()回去
private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }

從上面我們可以看到LiveData的數據更新以及數據回調的整個過程,但是當我們手動setValue()的時候過程是怎樣的呢?你會發現,setValue()其實最後就是通過調用了dispatchingValue()方法。而關於postValue()在子線程更新數據的相關代碼,這裏就不做介紹了,其實你大可以想出來,就是使用的Handler

LiveData中的代碼很簡潔,400多行的代碼,看起來也並不費勁,下面我們來分析下整個流程:

  • 通過使用LiveData對象,爲它創建觀察者Observer
  • 創建Observer時綁定Fragment生命週期
  • LifecycleBoundObserver生命週期變化時,dispatchValue下發更新LiveData中的值
  • LiveData主動setValue時,會主動dispatchValue,並且會considerNotify激活observer

4. 擴展

4.1 Map轉換

我們在開發中經常會遇到這種場景,有時我們需要根據另外一個LiveData實例返不同的LiveData實例,然後在分發給Observer,Lifecycle包提供了Transformations類,可以幫助我們實現這樣的場景:

通過**Transformations.map()**使用一個函數來轉換存儲在 LiveData對象中的值,並向下傳遞轉換後的值:

LiveDataViewModel

class LiveDataViewModel : ViewModel() {
    val data = listOf(User(0,"Hankkin"), User(1,"Tony"),User(2,"Bob"),User(3,"Lucy"))

    val id = MutableLiveData<Int>()
    //map轉換返回User實體
    val bean: LiveData<User> = Transformations.map(id, Function {
        return@Function findUserById(id.value!!)
    })
    //根據id查找User
    private fun findUserById(id: Int): User? {
        return data.find { it.id == id }
    }
}

LiveDataFragment

//改變ViewModel中idLiveData中的值
        btn_observer_map.setOnClickListener {
            mId++
            viewModel.id.postValue(mId)
        }
        //當idLiveData變化後,UserBean也會改變且更新Textview的文本
        viewModel.bean.observe(
            this,
            Observer { tv_livedata_map.text = if (it == null) "未查找到User" else "爲你查找到的User爲:${it.name}" })

4.2 Map源碼

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

我們可以看到map的源碼是通過MediatorLiveData中的addSource()方法來實現的,第一個參數爲我們需要改變的LiveData值,也就是我們上面例子中的userid,第二個參數則是我們傳過來的Fuction通過高階函數,將值set到LiveData上。

下面我們看下addSource()方法:

@MainThread
    public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
        Source<S> e = new Source<>(source, onChanged);
        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();
        }
    }

這裏把我們的LiveData和Observer封裝成了Source對象,並且這個對象,不能重複添加,具體代碼可查看Source:

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

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

        @Override
        public void onChanged(@Nullable V v) {
            if (mVersion != mLiveData.getVersion()) {
                mVersion = mLiveData.getVersion();
                mObserver.onChanged(v);
            }
        }
    }

首先Source是一個觀察者,可以看到,我們外部使用的Observer會以Source的成員變量的形式,添加到傳入的LiveData中。值得注意的是,這裏使用了mLiveData.observeForever(this);

observeForever()用法可以看到,我們並沒有傳遞LifecycleOwner,因此它並不具備生命感知能力。從註釋中也可見一斑:This means that the given observer will receive all events and will never be automatically removed.

map()的原理就是基於MediatorLiveData,MediatorLiveData內部會將傳遞進來的LiveData和Observer封裝成內部類,然後放在內部維護的一個Map中。並且自動幫我們完成observeForever()和removeObserver()

5.總結

  • LiveData基於觀察者模式實現,並且和LifecycleOwner進行綁定,而LifecycleOwner又被Fragment和Activity實現,所以它可以感知生命週期;在當前的LifecycleOwner不處於活動狀態(例如onPasue()onStop())時,LiveData是不會回調observe()的,因爲沒有意義.
  • 同時LiveData只會在LifecycleOwner處於Active的狀態下通知數據改變,果數據改變發生在非 active 狀態,數據會變化,但是不發送通知,等 owner 回到 active 的狀態下,再發送通知;
  • LiveData在DESTROYED時會移除Observer,取消訂閱,不會出現內存泄漏
  • postValue在異步線程,setValue在主線程
  • 如果LiveData沒有被observe(),那麼此時你調用這個LiveData的postValue(…)/value=…,是沒有任何作用

當然官方推薦我們LiveData配合ViewModel一起使用,因爲LiveData一般都出現在ViewModel中,所以我們下篇文章會繼續分析ViewModel.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章