- Android資料繫結技術一,企業級開發
- Android資料繫結技術二,企業級開發
- Android JetPack~ DataBinding(資料繫結)(一) 整合與使用
- Android JetPack~ LiveData (一) 介紹與使用
- Android JetPack~LiveData(二) 資料倒灌問題
- 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
- 設定android:configChanges="orientation|screenSize",這樣普通生命週期就不走了
待續。。。。。