天天看點

多線程調用LiveData的postValue如何保證隻展示最新值多線程調用LiveData的postValue如何保證隻展示最新值

多線程調用LiveData的postValue如何保證隻展示最新值

LiveData簡介

LiveData是一個資料持有類,它可以通過觀察者模式被android的Activity和Fragment等監聽,當LiveData的資料發生變化時,會通過onChanged方法通知頁面更新資料。

LiveData的優勢在于可以感覺元件的生命周期,隻有在元件是活躍狀态時才會通知元件更新(observe方法),當元件被destroy後,就算LiveData發生了變化也不會回調通知,且destroy後自動取消了元件的監聽,避免了記憶體洩露。

當發生Config Change時(比如螢幕旋轉),不需要通過手動處理處理資料的儲存( onSaveInstanceState ),LiveData會自動處理。

LiveData更新資料有兩個方法,setValue和postValue

  • setValue隻能在主線程使用
  • postValue可以在子線程和主線程使用,通過handler回到主線程設定

多線程使用postValue的問題

先貼上部分源代碼

protected void postValue(T value) {
   boolean postTask;
   // 鎖住
   synchronized (mDataLock) {
      // 目前沒有人在處理 post 任務
       postTask = mPendingData == NOT_SET;
       mPendingData = value;
   }
   if (!postTask) {
       return;
   }
   AppToolkitTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
   @Override
   public void run() {
       Object newValue;
       synchronized (mDataLock) {
           newValue = mPendingData;
		   // 處理完畢之後将 mPendingData 置為 NOT_SET
           mPendingData = NOT_SET;
       }
       //noinspection unchecked
       setValue((T) newValue);
   }
};
           

注意一點:mPendingData的類型是private volatile Object的,在主線程的runnable中是用mPendingData的值來更新的。

關于postValue的使用官方文檔有這麼一句

If you called this method multiple times before a main thread executed a posted task, only the last value would be dispatched.
           

大概意思是在主線程執行更新從postValue傳過來的值前(就是在runnable的鎖代碼塊完成前),如果調用了多次postValue,那麼隻有最新一次的值會被更新。

postValue時如何保證這個的呢?

一開始我看這個很疑惑,因為現在假設有兩個線程AB先後調用了同一個LiveData的postValue,先A後B,一開始A先拿到postValue中的鎖,此時postTask為True,mPendingData變成了A設的值a,然後通過handler走到主線程去執行,但在A拿到runnable中的鎖前,線程B提前拿到了postValue中的鎖,此時postTask變為False,mPendingData變為了B設的值b,此時B釋放鎖,然後因為postTask為false直接return,最後A再在主線程更新,這時不就是用值a來更新了嗎?這怎麼能做到隻有最新一次的值被更新?

LiveData通過volatile保證多次postValue隻會更新一次最新值

是的,因為mPendingData是volatile的,是以上述情況下,B更新mPendingData後,主線程中的mPendingData也會馬上更新從a為b(實際情況其實是讀的時候從記憶體讀時才更新),這樣的話值a就被重新整理成更新的b了,保證了多線程多次postValue隻有最新的值被更新

結論

LiveData的postValue通過volatile保證了同一個LiveData變量多次調用下也隻會更新最新的值,通過閱讀liveData的源代碼對多線程鎖和volatile的使用有了更深的了解。