LiveData的分析與簡單使用

  • 簡介

    • LiveData是androidx.lifecycle-livedata包下的一個抽象類,實現了一種關聯了生命週期的簡單觀察者模式,主要的功能就是用於視圖層與數據間的單向一對多通知,一個LiveData會持有一個可觀察的Data對象,一開始是處於NOT_SET狀態,當用戶經過setValue方法更新後,LiveData會遍歷全部的observer(處於Active狀態的),通知他們Data的更新.LiveData的行爲會在Lifecycle範圍內,避免不少Activity Leak和空指針
      本文代碼樣例都是kotlin,LiveData的源碼是java
  • LiveData的使用

    //聲明一個LiveData
      val data:MutableLiveData<String> = MutableLiveData()
      //在須要的地方訂閱,observer的onChange方法會回調
      data.observe(lifecycleOwner,observer)
      //能夠和retrofit配合使用
     interface ApiService {
        @GET("/api/get")
        fun getChannels():LiveData<ApiResponse<Page<Media>>>
      }
      //能夠和room配合使用
      @Dao
     interface BorrowModelDao {
    
          @Query("select * from s_borrow_moel")
         fun getAllBorrowedItems(): LiveData<List<BorrowModel>>
    
      }
      //配合ViewModel保存數據/監聽數據更改
      class MyViewModel:ViewModel(){
        val data:MutableLiveData<String> = MutableLiveData()
      }
    複製代碼
  • LiveData Tricks

    • Transformations.map方法轉換LiveData的數據類型
      好比咱們用Retrofit獲取了一個User類數據:LiveData,可是咱們只想把User.name暴露給外部觀察者,那麼咱們能夠這樣操做
    private val userLiveData:MutableLiveData<User> = MutableLiveData()
    val userNames:LiveData<String> = Transformations
    .map(userLiveData){
        user ->
        user.name
    }
    複製代碼

    Transformations在androidx.lifecycle包下java

    • MediatorLiveData
      MediatorLiveData能夠同時觀察多個LiveData的變化
      //聲明
        val mediatorLiveData:MediatorLiveData<String> = MediatorLiveData()
        //其餘合適的地方添加source
        mediatorLiveData.addSource(stringFromNetwork){
            mediatorLiveData.value = it
        }
        mediatorLiveData.addSource(stringFromDatabase){
            mediatorLiveData.value = it
        }
      複製代碼
  • 配合ViewModel使用

    • 咱們知道ViewModel能夠在一個LifecycleOwneronCreateOnDestroy之間保存實例不受到屏幕旋轉等ConfigChange的影響
      因此能夠經過Activity/Fragment持有ViewModel,而ViewModel持有各種LiveData,Activity/Fragment註冊觀察須要的數據,實現數據與UI的同步,並且不會所以發生Activity泄漏,甚至能夠用ViewModel來進行Activity/Fragment之間的通信
  • 關於Lifecycle

    • Lifecycle組成

      • LifecycleOwner: Activity/Fragment都是LifecycleOwner(support包下的AppCompatActivity和對應的Fragment),他是androidx.lifecycle:lifecycle-common包下的一個藉口,只有getLifecycle()一個方法,返回一個Lifecycle對象
      • Lifecycle: 而這個Lifecycle就是維護生命週期state的主體,默認實現是LifecycleRegistry,這個提及來也挺長的,之後有空再新的文章裏仔細說明,反正如今讀者只要知道咱們經常使用的AppCompatActivity/Fragment都是能夠拿到生命週期Lifecycle的就好了
      • LifecycleObserver: 也是一個接口,不過它一個抽象方法也沒有,若是咱們須要一個新的自定義的觀察 者,只要實現這個接口,而後在須要對應生命週期方法回調的方法上添加
        OnLifecycleEvent註解並添加對應註解就行了,LiveData有一個 LifecycleBoundObserver內部類實現了這個接口,不過繼承關係是這樣的 LifecycleObserver <--GenericLifecycleObserver <- LifecycleBoundObserver,
        LifecycleBoundObserver會在onStateChange收到回調,不依賴於註解,不過讀 者如今只要知道在Lifecyclestate發生改變的時候,LifecycleObserver會收 到通知(void onStateChanged(LifecycleOwner source, Lifecycle.Event event);)

xianyu.gif

  • LiveData類分析

    • 簡單的類結構
      有幾個內部類,都是ObserverWrapper的子類,用於普通的觀察者(帶生命週期)的LifecycleBounderObserver,和不帶的AlwaysActiveObserver..
    abstract class LiveDate{
    
        class LifecycleBounderObserver extends ObserverWrapper implements GenericLifecycleObserver{
    
        }
    
        private abstract ObserverWrapper{
    
        }
    
        private class AlwaysActiveObserver extends ObserverWrapper {
    
        }
      }
    複製代碼
  • observe入手分析

    • 傳入參數: LifecycleOwner , Observer類(簡單的回調通知接口)
    • 首先經過LifecycleOwner獲取Lifecycle,判斷時候是DESTROYED狀態,是的話直接return 將ObserverLifecycleOwner包裝爲LifecycleBoundObserver對象
    • LiveData維護了一個SafeIterableMap<Observer<? super T>, ObserverWrapper> 對象mObservers,保存了Observer和對應的Wrapper,存入LifecycleBoundObserver對象後判斷是否已存在而且是否對應當前LifecycleOwner,作出相應的處理,當mObservers中沒有時,直接給LifecycleOwner的Lifecycle註冊該LifecycleBoundObserver
    • 因此說其實是咱們傳入的LifecycleOwner保存的Lifecycle註冊了一個觀察者,LifecycleBoundObserver會在state 等於 DESTROYED的時候移除該觀察者,在其餘狀態的時候調用activeStateChange()方法
    • 先比較當前mActive和新active,賦值給mActive,而後經過LiveData類的mActivieCount是否爲0來判斷是否是徹底沒有通知過,若是是進入非active狀態mActiveCount就-1,不然+1,原先未active如今active了,調用onActive方法,新的mActivieCount == 0而且 新active的狀態爲false就調用onInactive方法,而後判斷mActive,true則會調用dispatchValue方法,基本上mActivieCount只會有0 -> 1 ,1 -> 0兩個狀態變化,因此onActive是LiveData觀察者數量從無到有時回調,onInactive反之
      private abstract class ObserverWrapper {
       final Observer<? super T> mObserver;
       boolean mActive;
       int mLastVersion = START_VERSION;
       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);
           }
       }
      複製代碼

} ```android

  • 上面羅裏吧嗦一大推讀者可能一臉懵逼,反正結論就是,LiveData狀態由沒有觀察者到有觀察者會走onActive方法,反之會走onInactive方法,無論原先狀態如何,只要新狀態是活躍就會走dispatchValue
  • onInactive/onActiveLiveData裏兩個open protected的方法,只在MediatorLiveData裏有實現,我尚未仔細研究MediatorLiveData,你們能夠去看看源碼
  • 因此LifecycleBoundObserver新狀態爲活躍時,會調用外部類LiveDatadispatchValue方法,傳入的參數爲ObserverWrapper,也就是LifecycleBoundObserver的父類(LifecycleBoundObserver繼承了ObserverWrapper,實現了GenericLifecycleObserver),在這要注意下內部類(非靜態)是能夠拿到外部類實例的,LiveData.this.XXX,忘記的同窗複習下,我是很久沒用java,忽然看到有點懵逼..
//傳入參數是Observer,有的話就分發給它,爲null就對全部Observers分發數據
void dispatchingValue(@Nullable ObserverWrapper initiator) {
  //若是正在分發數據,就標記爲分發無效,分發中的會所以跳出循環
   if (mDispatchingValue) {
     //標記爲分發無效
       mDispatchInvalidated = true;
       return;
   }
   //標記爲分發中
   mDispatchingValue = true;
   do {
       mDispatchInvalidated = false;
       if (initiator != null) {
           considerNotify(initiator);
           initiator = null;
       } else {
           for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                   mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                //嘗試分發
               considerNotify(iterator.next().getValue());
               //標記爲無效時會跳出循環,在while循環中等待一次mDispatchInvalidated再次變爲true時再次進入for循環
               if (mDispatchInvalidated) {
                   break;
               }
           }
       }
       //沒有被標記無效時while循環就執行一次完事,不然會再次執行
   } while (mDispatchInvalidated);
   mDispatchingValue = false;
}
複製代碼
  • LiveData中的mDispatchingValue/mDispatchInvalidated在此處保證不會重複分發或者分發舊的value,當setValue分發調用dispatchValue(null)時會遍歷全部的Observer分發新值,不然只分發給傳入的ObserverWrapper,這裏說明下:LiveData維護了mDispatchingValue/mDispatchInvalidated,而Observer可能會有多個,都持有LiveData對象(由於是內部類),因此等待的observer對應的LiveData會得到mDispatchInvalidated = true,中斷進行中的分發,讓舊數據再也不分發
  • considerNotify: 第一步檢查ObserverWrapper是否mActive,第二步檢查shouldBeActive(),第三步檢查ObserverWrapper的版本observer.mLastVersion >= mVersion,最後才通知更新,調用Observer的onChange方法
  • ObserverWrapper中的mLastVersion /和LiveData的mVersion用來防止再入活躍狀態後重復分發
  • ObserverWrapper中的mActive用來控制該觀察者是否須要分發(activeStateChanged(boolean)方法的做用下)
  • considerNotify方法

    先上代碼
    private void considerNotify(ObserverWrapper observer) {
         if (!observer.mActive) {
             return;
         }
         // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
         //
         // we still first check observer.active to keep it as the entrance for events. So even if
         // the observer moved to an active state, if we've not received that event, we better not
         // notify for a more predictable notification order.
         if (!observer.shouldBeActive()) {
             observer.activeStateChanged(false);
             return;
         }
         if (observer.mLastVersion >= mVersion) {
             return;
         }
         observer.mLastVersion = mVersion;
         //noinspection unchecked
         observer.mObserver.onChanged((T) mData);
     }
    
    複製代碼
    很簡單的邏輯,就是
    1. 第一步判斷是否active,這個mActive屬性在幾種狀況下會爲true
      a. Observer是經過observeForever註冊的
      b. Observer的shouldBeActive返回true 咱們看看方法代碼,只有綁定的Lifecycle的State大於STARTED纔會爲true
@Override
            boolean shouldBeActive() {
                return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
            }
複製代碼
mActive會在生命週期變化時會被屢次檢查
2. 第二步再次檢查`shouldBeActive()`狀態
3. 第三步檢查`mLastVersion`和`mVersion`  
    這個version是在setValue時被+1的,檢查一下防止重複分發,完成後修改lastVersion而後回調`onChange(T)`
複製代碼
  • setValue/postValue方法的分析

    按慣例先看看代碼,postValue的代碼也好理解,只是給賦值操做加了一個鎖,並把setValue放到主線程執行,使多個postValue只有最後一個的value生效api

    private final Runnable mPostValueRunnable = new Runnable() {
       @Override
       public void run() {
           Object newValue;
           synchronized (mDataLock) {
               newValue = mPendingData;
               mPendingData = NOT_SET;
           }
           //noinspection unchecked
           setValue((T) newValue);
       }
    };
    protected void postValue(T value) {
       boolean postTask;
       synchronized (mDataLock) {
           postTask = mPendingData == NOT_SET;
           mPendingData = value;
       }
       if (!postTask) {
           return;
       }
       ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }
    
    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }
    複製代碼

    想象一下若是兩個線程T-A,T-B 裏都執行了postValue傳入不一樣的值A,B,先會在方法內的mDataLock鎖住的代碼塊競爭執行,好比A先執行,mPendingData先被賦值爲A,postTask => true,而後賦值爲B,也就是說第一次的賦值纔會經過同步塊以後的if判斷,執行分發runnable,線程T-B只是修改了mPendingValue的值app

    而後會有一個主線程上的同步代碼塊(也是同一個鎖),將新值執行setValue,mPendingValue重設爲初始值,也就是說取得值其實是後一個線程的B,後面分發完成重設爲NOT_SET,後面的PostValue又進入原來的邏輯了ide

    postValue的註釋也很清楚了: If you called this method multiple times before a main thread executed a posted task, only the last value would be dispatched.工具

  • 基本流程

    • observe() -> 新建Observer -> Observer的StateChange -> dispatchValue -> considerNotify
    • setValue/postValue -> dispatchValue -> considerNotify
  • 總結

    LiveData的結構是比較簡單的,使用時注意不要屢次註冊觀察者,通常若是在Activity中使用,就在OnCreate方法註冊,Activity被關閉或回收後觀察者會自動解除訂閱,因此不會發生泄漏,咱們也能夠本身繼承LiveData作更多的定製來實現本身的業務邏輯,配合Tranformations工具類和MediatorLiveData能夠實現不少比較複雜的邏輯post

相關文章
相關標籤/搜索