當前位置:編程學習大全網 - 源碼下載 - 把 LiveData 用於事件傳遞那些坑

把 LiveData 用於事件傳遞那些坑

利用觀察者模式打造的事件總線的優點不必多說(當然也有很多缺點),如 EventBus 和 RxBus 用的好的話能起到很好的解耦作用,使整個程序架構更加清晰,不至於到處傳遞各種 Callback。但是他們都缺少了對 View 層(Activity、Fragment 等)的生命周期的感知能力,需要在生命周期結束時手動解除觀察者,手動管理生命周期十分繁瑣且很容易出錯。

而 Google 推出的 Lifecycle 庫就是為了解決這壹問題,其中的 LiveData 就是壹個具有生命周期感知能力的觀察者,如果用它來打造壹個能夠感知生命周期的事件總線,豈不美哉!

在隨著對 LiveData 的運用和理解的逐漸深入,特別是對它的「生命周期感知能力」有了更深的理解,慢慢發現這樣用的壹些坑,借此機會就跟大家分享探討壹下。而且我平時也有把 LiveData 純粹當作事件傳遞來用,特別是列表操作(比如涉及 IO 的增刪操作,View 層需要知道哪個數據改動了,以及操作是否成功等,只能以事件的形式傳遞)。

在我的前壹篇文章中也提到過,大家也可以直接看源碼。postValue 只是把傳進來的數據先存到 mPendingData,然後往主線程拋壹個 Runnable,在這個 Runnable 裏面再調用 setValue 來把存起來的值真正設置上去,並回調觀察者們。而如果在這個 Runnable 執行前多次 postValue,其實只是改變暫存的值 mPendingData,並不會再次拋另壹個 Runnable。這就會出現後設置的值把前面的值覆蓋掉的問題,會導致事件丟失。

LiveData 的生命周期感知能力就體現在這裏,它不會回調處於「非激活狀態」(即 onStart 之後到 onPause 之前)的觀察者,因為這時更新 View 沒有意義,而且比較危險,它會等到觀察者激活之後再把新的值回調給他。

但是如果我傳了多個數據(假設都是用 setValue 保證不會被覆蓋),那些處於非激活狀態的觀察者是毫不知情的,他們在激活的時候只會收到最後壹個數據。這對於事件傳遞來說,就表現為事件丟失,中間傳的任何數據都無法收到,那也就失去了事件傳遞的意義。

從上面兩點也可以看出, LiveData (或者說它的觀察者) 在觀察者激活之前並不關心中間經歷過多少次數據變更,它只會在某個觀察者激活時,傳遞給他最新的值,中間的值都不會起作用。

當然 LiveData 的設計也不是為了傳遞事件的,它是為了反應 View 當前狀態的, View 層只需要根據當前 LiveData 的值去渲染數據就行,非激活狀態時 View 都不可見,就算更新了也沒意義。

我最開始也是覺得 LiveData 用到了觀察者模式,而且可以進行壹些不同 Fragment 之間數據通訊,就想到了事件總線,現在想想當時還是 too young too naive。

當然,也不是說 LiveData 也不是沒救了,有谷歌給我們提供了強大的 Lifecycle 庫,我們完全可以自己造壹個不會丟事件的 LiveData 。

LiveData 的其他功能做的很完善,只是會丟事件,我們要改造就要就針對上面的問題逐個擊破。

對於 postValue 的問題,既然它最後也是調用的 setValue,丟數據是因為只拋了壹次 Runable,那我們就自己每次都往主線程拋壹個 Runable 就能解決這個問題

其實我覺得這個問題的主要「責任」並不在 LiveData,而是在它的觀察者,「是妳告訴我妳非激活的呀,那我怎麽給妳發數據呢,我發給妳,萬壹妳出問題了呢,那到底誰負責?」。

我們常用的觀察者其實是 LifecycleBoundObserver,在調用 public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) 會自動幫我們封裝壹個這樣的觀察者,而它會根據 LifecycleOwner 的生命周期呈現出「激活」和「非激活」狀態。

LiveData 默認的還有另外壹種觀察者 AlwaysActiveObserver,它是我們在調用 public void observeForever(@NonNull Observer<? super T> observer) 時生成的,顧名思義它會壹直處於激活狀態,LiveData 當然也不會替我們管理這樣觀察者的生命周期,我們需要在不使用時手動調用 public void removeObserver(@NonNull final Observer<? super T> observer) 移除觀察者,否則可能會內存泄漏。

這個 AlwaysActiveObserver 看樣子能夠解決我們的問題,他壹直處於激活狀態,那所有的事件都會回調給他,但是需要我們自己管理生命周期。這不是開歷史倒車嗎?好不容易有生命周期感知了,現在又要自己手動搞?

手動管理生命周期是絕對不能忍的,AlwaysActiveObserver 可以解決剛才說的問題,那我們就造壹個新的觀察者來管理 observeForever 和 removeObserver 的問題。既然要造,那就造個好用的,首先事件壹定不能丟,要不就沒意義了;而且生命周期要觀察者自己管理,不能只是簡單的 observeForever 和 removeObserver,非激活狀態之類的也要考慮進去。

既然要管理生命周期,那就不得不用到 LifecycleOwner、Lifecycle,然後自己觀察 LifecycleOwner 的 Lifecycle。

Lifecycle 對外只給了這個接口,並不含有任何回調,我們需要用註釋裏說的 OnLifecycleEvent 註解來標記相應的函數,Lifecycle 會通過反射拿到標記的函數,然後生成對應的適配器,感興趣的可以看下 Lifecycling.getCallback 函數。比如我們可以這樣用

拿到生命周期後,我們就可以在壹開始 observeForever ,在 Lifecycle.Event.ON_DESTROY 時 removeObserver 。

接下來就要考慮激活和非激活的狀態了,既然用了 observeForever ,那每次事件都會有回調,這時候如果 Lifecycle 處於激活狀態,那可以直接把事件發出去。但如果非激活,不能直接把事件發出去,又不能丟,那我們就需要先把事件存起來,然後在 Lifecycle 變為激活狀態時再把存起來的事件發送出去。簡單畫了下流程圖。

3.1 也說過要自己處理 postValue,其次要保證用我們自己定義的觀察者,需要重寫 public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)。

這個工具包裏還有其他壹些我平時常用的小工具,這裏簡單分享下:

  • 上一篇:python中sys是什麽模塊
  • 下一篇:求家常素菜的菜譜
  • copyright 2024編程學習大全網