Android JetPack~LiveData(二) 資料倒灌問題

TMusketeer發表於2023-05-02
  1. Android資料繫結技術一,企業級開發
  2. Android資料繫結技術二,企業級開發
  3. Android  JetPack~ DataBinding(資料繫結)(一)    整合與使用
  4. Android  JetPack~ LiveData (一)   介紹與使用
  5. Android JetPack~LiveData(二) 資料倒灌問題
  6. Android  JetPack~ ViewModel (一)   介紹與使用

1、資料倒灌的出現

場景:

如果我們在一個home頁面獲取網路資料,然後透過LiveData的觀察者特性,在回撥中跳轉B頁面,當旋轉螢幕時,頁面重建,LiveData又發來最後一次資料,那麼直接觸發了跳轉B頁面的程式碼。這就是資料倒灌引起的問題。因為LiveData的資料會儲存在記憶體中。

資料倒灌原因:

個人描述:我們都知道LiveData是一個觀察者模式,被觀察者只要改變了觀察者會收到通知。在頁面重建時,LiveData自動推送最後一次資料供我們使用。
官方描述:ViewModel 將資料保留在記憶體中,這意味著開銷要低於從磁碟或網路檢索資料。ViewModel 與一個 Activity(或其他某個生命週期所有者)相關聯,在配置更改期間保留在記憶體中,系統會自動將 ViewModel 與發生配置更改後產生的新 Activity 例項相關聯。
 
在分發事件的時會先判斷mVersion 和mLastVersion,當mLastVersion < mVersion時會onChanged((T) mData);進行分發。每次設定setValue時mVersion++,然後賦值給mLastVersion。
private abstract class ObserverWrapper {
    final Observer<? super T> mObserver;
    boolean mActive;
    // 第一處
    int mLastVersion = START_VERSION;
}
    private void considerNotify(ObserverWrapper observer) {
        ...
        // 第二處
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        // 第三處
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }
從上面實驗結果可知,螢幕旋轉前,observer.mLastVersion == mVersion ==2。但是螢幕旋轉後,mLastVersion的值卻變成了-1。這裡就是問題所在了。
 
 

倒灌原因小結

Activity異常銷燬然後重建,ViewModel會儲存銷燬之前的資料,然後在Activity重建完成後進行資料恢復,所以LiveData成員變數中的mVersion會恢復到重建之前的值。
但是Activity重建後會呼叫LiveData的observe()方法,方法內部會重新new一個例項,會將mLastVersion恢復到初始值。
由於LiveData本身的特性,Activity的生命週期由非活躍變成活躍時,LiveData會觸發事件分發,導致螢幕旋轉或者切換系統語言後出現資料倒灌。
 

注意

但是這裡有一點要非常注意:系統記憶體不足,殺到應用後臺,也會導致Activity重建,但是不會LiveData導致資料倒灌。
問題找到了,那如何防止資料倒灌呢?

解決辦法

再來回顧下,資料倒灌的常見方式:
  • 螢幕旋轉
  • 使用者手動切換系統語言
方案:
  • 如果應用不需要橫屏,就設定為永久豎屏。
  • 如果當前Activity回到前臺LiveData不需要接收最新的資料,可以使用下面三中擴充套件的LiveData

 

待續。。。。。

 

 

 

相關文章