Jetpack ——LiveData初識到源碼解析(一)

上篇博客分享了下Lifecycle,使用的技術也就是:觀察者模式+註解+反射。本篇博客繼續學習Jetpack的LiveData,其實這個東西是一種可觀察的數據存儲類。

LiveData自己可以作爲觀察者,觀察到數據變化,並回調給開發者。 它是可以監聽到Activity(Fragment)生命週期的變化,並且在Activity處於活躍狀態下,才發送時間通知開發者處理業務邏輯。

LiveData官網

這個LiveData不是數據,是數據存儲類。

LiveData的使用

示例:一個按鈕,一個TextView , 點擊一個按鈕,TextView的值+1。

LiveData一般是結合ViewModel使用的,關於ViewModel,之後的博客再分享。 先創建一個類繼承自ViewModel:

/**
 * author: liumengqiang
 * Date : 2020/5/14
 * Description :
 */
public class NameViewModel extends ViewModel {

	//MutableLiveData繼承自LiveData
    private MutableLiveData<String> name;

	//暴露獲取方法
    public MutableLiveData<String> getName() {
        if(name == null) {
            name = new MutableLiveData<>();
        }
        return name;
    }
}

使用的話就很簡單了, 在Activity的onCreate方法中:

    private int index = 0;

    private TextView nameTextView;

    private Button btn;

    private NameViewModel nameViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_live_data);
		//獲取或者創建ViewModel
        nameViewModel =
                new ViewModelProvider(this,
                        new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(NameViewModel.class);

		//綁定LiveData到一個觀察者上
        nameViewModel.getName().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                nameTextView.setText(s);
            }
        });

        nameTextView = findViewById(R.id.live_data_text);
        btn = findViewById(R.id.live_data_btn);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
            	//數據源改變
                String name = "hello world " + (index ++);
                nameViewModel.getName().setValue(name);
            }
        });
    }

這個代碼就很簡單了,結果如下圖:

這個例子是很簡單的,LiveData強大之處就是: 既可以作爲觀察者,也可以作爲被觀察者。

作爲觀察者:能夠感知Activity或者Fragment的生命週期的變化。
作爲被觀察者:當數據改變能夠通知給開發者,以處理業務邏輯。

其內部原理是怎樣的呢?

LiveData源碼分析

在分析源碼之前我們看三個結論,

  • LiveData是能夠感知組件生命週期的,當Activity處於活躍狀態時,才能夠收到數據,不處於活躍狀態是收不到事件的。
  • LiveData在組件處於DESTROYED狀態下會移除Observer,解除綁定,避免內存泄漏
  • 每次調用setValue更改數據源之後,如果組件從非活躍狀態到活躍狀態,組件此時接收到的是最新的數據,而中間發的很多的次變更都是無效的。

首先我們從訂閱開始:

    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    	//檢測是否在主線程
        assertMainThread("observe");
        //判斷組件是否是DESTROYED狀態。
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        //將組件和Observer封裝成一個對象:LifecycleBoundObserver
        //這個對象實現了LifecycleObserver接口
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        //把所有的Observer和封裝的對象添加到了集合中
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
       	......
       	//這個是把LifecycleObserver實現對象和 組件綁定起來
       	//這樣就能夠感知組件的生命週期了。
        owner.getLifecycle().addObserver(wrapper);
    }

這裏做了主要三件事

  1. 檢測組件是否是處於DESTORYED狀態, 如果是,就直接返回
  2. 將組件和Observer封裝成了一個LifecycleObserver實現類對象,這個對象,存到了一個map中,這樣方便之後setValue分發數據
  3. 最後將LifecycleObserver實現類對象和組件綁定在一起,這樣能夠感知組件的生命週期變化了。

現在看下setValue方法,也就是改變LiveData裏面的數據源

	//從這個註解可以看出來必須要在主線程調用
    @MainThread
    protected void setValue(T value) {
    	// 檢測是否在主線程
        assertMainThread("setValue");
        //定義了一個版本號
        mVersion++;
        //將值賦值給mData變量
        mData = value;
       	//開始分發數據事件
        dispatchingValue(null);
    }

代碼註釋比較清晰了,主要是這個版本號:mVersion是個什麼東西呢? 爲什麼定義這個東西呢? mVersion就是記錄一下改變次數,每次setValue方法調用,也就是每次數據源改變,mVersion都會+1, 這個值接下來會和LifecycleBoundObserver實現類的mLastVersion對比的,具體下文解釋。

然後將value值賦值給了mData對象,這樣的話,試想一下,如果若此調用setValue方法,每次set 的值都不一樣,那麼是不是mData存儲的都是最後一次setValue的值呢? 答案是肯定的,存儲的就是最後一次setValue的值。

然後現在開始分發數據源改變的事件:

   @SuppressWarnings("WeakerAccess") /* synthetic access */
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
      ........
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
            	//initiator不是null, 也就是定向分發事件,
                considerNotify(initiator);
                initiator = null;
            } else {
            	//initiator是null
            	//	循環之前map, 然後給每個觀察者都分發事件
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

由於此時傳入的dispatchingValue傳入的參數是null,所以是全部的觀察者都分發事件。

傳入initiator不是null的情況是在生命週期改變的情況下執行的,下文具體分析

    private void considerNotify(ObserverWrapper observer) {
        //判斷是否是處於活躍狀態
        //是否是已經解綁
        if (!observer.mActive) {
            return;
        }
        //活躍狀態是:STARTED或者RESUMED
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        //判斷Observer的mLastVersion和mVersion的大小
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        //給Observer的mLastVersion重新賦值
        observer.mLastVersion = mVersion;
        //noinspection unchecked
        //執行觀察者的onChaned回調
        observer.mObserver.onChanged((T) mData);
    }

這裏的ObserverWrapper observer對象實際上就是LifecycleBoundObserver, 這個在剛開始訂閱的時候內部創建的。它繼承自ObserverWrapper

LifecycleBoundObserver也實現了GenericLifecycleObserver,而GenericLifecycleObserver繼承自LifecycleEventObserver, 這個細節很重要,具體後續的代碼會着重分析。

   class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }

		//判斷是否是活躍狀態:STARTED或者RESUMED,
        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

		//這個方法就是組件生命週期改變時, 調用的方法。傳入的參數一個是組件本身,一個是組件處於的狀態
        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        	//當組件處於DESTROYED狀態時,也就是處於銷燬狀態時
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            	//移除Observer,解除綁定
                removeObserver(mObserver);
                return;
            }
            //這個方法的實現是在父類ObserverWrapper中的
            activeStateChanged(shouldBeActive());
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }

從LifecycleBoundObserver的具體實現,需要注意兩個知識點

  1. shouldBeActive方法是返回組件是否:STARTED或者RESUMED狀態,如果是就返回true
  2. onStateChanged方法是分析LiveData感知組件生命週期的重要點,具體我們下文分析。

在onStateChanged方法中調用了父類的activeStateChanged方法,看下具體實現:

       void activeStateChanged(boolean newActive) {
       		//判斷活躍狀態是否等於上一次的狀態
            if (newActive == mActive) {
                return;
            }
            ......
           //
            if (mActive) {
            	//如果是活躍狀態,那麼就分發數據源改變事件,傳入的參數是自己本身,
            	//也就是:LifecycleBoundObserver類的對象
                dispatchingValue(this);
            }
        }
    }

這時候對於dispatchingValue方法傳入的參數不是null, 是不是就是單次分發呢? 懵逼的,重新網上看下dispatchingValue方法。,進入到了if判斷裏面。

重新回到considerNotify方法,mLastVersion和mVersion的初始值都是-1, 但是每次setValue, mVersion的值都會+1, 但是mLastVersion的值還是-1, 所以(observer.mLastVersion >= mVersion) 不成立,將mVersion的值賦值給mLastVersion, 這樣mLastVersion就是最新的值了, 最後調用了我們熟悉的onChanged方法。

想一下considerNotify方法中爲什麼會有這三個if判斷呢?
首先前兩個判斷就是要保證組件處於活躍狀態; 此三個判斷就是要保證只接受最後一次的新數據,並且只執行一次。 Google這樣設計也是相當的巧妙!

這樣每次setValue 到 執行onChange方法流程就分析完了。

那麼它是怎樣感知生命週期的呢? 換句話說就是LifecycleBoundObserver的onStateChanged方法是什麼時候執行的呢?

這個問題,如果是看過Lifecycle源碼的,這個問題是相當簡單的。

Lifecycle源碼分析

記不記得我們剛開始調用LiveData的observe方法的時候,該方法的最後一句話:

owner.getLifecycle().addObserver(wrapper);

把封裝成的LifecycleBoundObserver類對象和組件綁定到了一塊, 這樣內部就通過 ReportFragment就能夠感知生命週期的變化了。詳見:Lifecycle源碼分析

這裏需要注意的一點是,當生命週期變化的時候,最終調用的dispatchEvent方法:

    static class ObserverWithState {
        State mState;
        LifecycleEventObserver mLifecycleObserver;

        ObserverWithState(LifecycleObserver observer, State initialState) {
        	//這裏返回的直接是將observer轉成了LifecycleEventObserver。
            mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
            mState = initialState;
        }

        void dispatchEvent(LifecycleOwner owner, Event event) {
            State newState = getStateAfter(event);
            mState = min(mState, newState);
            //調用了觀察者的onStateChanged方法
            mLifecycleObserver.onStateChanged(owner, event);
            mState = newState;
        }
    }

這裏的observer參數就是LifecycleBoundObserver類對象,上文說過LifecycleBoundObserver實現了LifecycleEventObserver接口,Lifecycling.lifecycleEventObserver(observer);內部執行一通邏輯之後,做的操作是直接將observer轉成了LifecycleEventObserver接口對象。

ReportFragment生命週期的變化之後,調用的是LifecycleBoundObserver的onStateChanged方法,這樣是不是形成了閉環?!

重新理一下步驟:

setValue ——> onChanged流程

  1. 通過調用LiveData的observe方法,創建了LifecycleBoundObserver對象,並且綁定了組件和LifecycleBoundObserver實例。
  2. 每次setValue之後會調用dispatchingValue方法
  3. 在dispatchingValue方法內,會調用considerNotify方法
  4. 在considerNotify方法內,回到用觀察者的onChanged方法。

感知LiveData生命週期流程

  1. 通過調用LiveData的observe方法, 在這個方法最後一句話,綁定了組件和LifecycleBoundObserver類的實例對象。
  2. LifecycleRegister的addObserver方法內,將LifecycleBoundObserver類實例存儲到了一個map中。
  3. 在組件的內部創建了一個空白的ReportFragment, ReportFragment的生命週期是和組件的生命週期是同步的。
  4. 以Report Fragment的onStart方法爲例: 內部調用了dispatch(Lifecycle.Event.ON_START);
  5. dispatch方法內調用handleLifecycleEvent方法, 該方法是在LifecycleRegister類內部的
  6. handleLifecycleEvent ——》 moveToState ——》 sync ——》 forwardPass ——》 dispatchEvent ——》 mLifecycleObserver.onStateChanged
  7. 最後回到了LifecycleBoundObserver的onStateChanged方法內,調用:activeStateChanged方法
  8. activeStateChanged ——》 dispatchingValue ——》 considerNotify ——》onChanged方法

這樣整個流程就完全了, 可能感知生命週期的流程比較懵逼的話,一定要看一下:Lifecycle源碼分析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章