一、LiveData 介紹
LiveData是 Google 推薦的 Android 架構組件之一,是一個基於觀察者模式的數據容器,但與一般的被觀察者不同的是,它是有生命周期感知功能,解決了Android開發者需要去手動處理生命周期的痛點。
它具備如下特點:
① 數據可以被觀察者訂閱。
② 能夠感知組件(Fragment、Activity、Service)的生命周期。
③ 只有當組件處於活躍狀態(STARTED或RESUMED)時才會通知觀察者數據發生了變化。
官方對其優點說明概括如下:
① UI和實時數據保持一致
因為LiveData采用了觀察者模式,LiveData是被觀察者,所以當數據有變化時觀察者(UI)就會獲得通知,並進行更新。
② 避免內存泄漏
當被綁定的組件處於DEDTROYED狀態時,觀察者對象會自動清理自身的數據。
③ 當Activity停止時不會引起崩潰
當組件處於非激活狀態時,它不會收到任何LiveData中數據變化的通知。
④ 不需要額外的處理來響應生命周期的變化
LiveData可以自動感知被綁定的UI組件的生命周期,只有當UI組件處於活躍狀態時才會通知數據變化。
⑤ 始終保持最新的數據
當組件從不活躍狀態變為活躍狀態時總是可以收到最新的數據
⑥ 解決了Configuration change問題
當Activity或Fragment由於配置變化(如用戶旋轉了設備屏幕)而被重新創建時,能夠立刻收到最新的數據。
⑦ 資源共享
我們可以實現一個單例模式的LiveData子類,並將系統服務封裝在該類中。這樣,任何需要這些系統服務的觀察者就可以通過觀察這個LiveData子類對象實現資源的共享。
二、LiveData的使用
LiveData組件相關的類和接口有:LiveData類、Observer接口、GenericLifecycleObserver接口和LifecycleOwner接口。
1. LiveData是個抽象類,MediatorLiveData繼承自MutableLiveData,MutableLiveData則繼承自LiveData。MediatorLiveData可以看成是多個LiveData的代理,MutableLiveData則是提供了可以修改LiveData中數據的對外公開方法。
2. LiveData有3個內部類ObserverWrapper、AlwaysActiveObserver和LifecycleBoundObserver,其中后兩個類都是ObserverWrapper的子類。LifecycleBoundObserver實現了GenericLifecycleObserver接口,當LifecycleOwner的生命周期變化時就會通過該接口的onStateChanged()方法回調回來。
3. Observer接口就是觀察者,它定義了LiveData數據變化的回調方法onChanged()。MediatorLiveData的內部類Source實現了該接口。
使用步驟如下:
1. 創建一個持有某種數據類型的LiveData對象。
2. 創建一個觀察者對象,通常在UI Controller(如Activity或Fragment)中創建這個觀察者。
3. 將觀察者對象作為參數傳入LiveData.observe()方法,連接觀察者和LiveData。
2.1 創建LiveData對象
public class NameViewModel extends ViewModel { // Create a LiveData with a String private MutableLiveData<String> mCurrentName; public MutableLiveData<String> getCurrentName() { if (mCurrentName == null) { mCurrentName = new MutableLiveData<String>(); } return mCurrentName; } // Rest of the ViewModel... }
2.2 觀察LiveData對象
通常情況下都是在組件的onCreate()方法中開始觀察數據,原因有以下兩點:
① 系統會多次調用onResume()方法
② 確保Activity或Fragment在處於活躍狀態時立刻可以展示數據。
public class NameActivity extends AppCompatActivity { private NameViewModel mModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Other code to setup the activity... // Get the ViewModel. mModel = ViewModelProviders.of(this).get(NameViewModel.class); // Create the observer which updates the UI. final Observer<String> nameObserver = new Observer<String>() { @Override public void onChanged(@Nullable final String newName) { // Update the UI, in this case, a TextView. mNameTextView.setText(newName); } }; // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer. mModel.getCurrentName().observe(this, nameObserver); } }
2.3 更新LiveData對象
LiveData 沒有提供可用的公共方法來更新其持有的數據,但是如果我們使用LiveData的子類MutableLiveData
來存儲數據,那么我們就可以使用它的公共方法setValue()
和postValue()
方法更新數據。
mButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { String anotherName = "John Doe"; mModel.getCurrentName().setValue(anotherName); } });
2.4 繼承LiveData類
當然我們也可以通過繼承LiveData定義自己的擴展類:
public class StockLiveData extends LiveData<BigDecimal> {
private StockManager mStockManager; private SimplePriceListener mListener = new SimplePriceListener() { @Override public void onPriceChanged(BigDecimal price) { setValue(price); } }; public StockLiveData(String symbol) { mStockManager = new StockManager(symbol); } @Override protected void onActive() { mStockManager.requestPriceUpdates(mListener); } @Override protected void onInactive() { mStockManager.removeUpdates(mListener); } } public class MyFragment extends Fragment { @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); LiveData<BigDecimal> myPriceListener = ...; myPriceListener.observe(this, price -> { // Update the UI. }); } }
自定義的StockLiveData實現了LiveData中的空方法onActive()
和onInactive()
。
三、LiveData 的原理
3.1 數據發生變化時LiveData如何通知 Observer?
LiveData提供了兩種添加觀察者的方法:observe()
和observeForever()
:
@MainThread public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) { if (owner.getLifecycle().getCurrentState() == DESTROYED) { // ignore return; } //將LifecycleOwner對象和Observer對象封裝成LifecycleBoundObserver對象 LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); // mObservers是一個SafeIterableMap類型的數據容器,通過它的putIfAbsent()方法可以判斷Observer對象是否已經與一個LifecycleBoundObserver對象關聯 ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); if (existing != null && !existing.isAttachedTo(owner)) { throw new IllegalArgumentException("Cannot add the same observer with different lifecycles"); } if (existing != null) { return; } //注冊傳入的觀察者對象的生命周期監聽 owner.getLifecycle().addObserver(wrapper); } @MainThread public void observeForever(@NonNull Observer<T> observer) { AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer); ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) { throw new IllegalArgumentException("Cannot add the same observer with different lifecycles"); } if (existing != null) { return; } wrapper.activeStateChanged(true); }
如果通過observeForever()
方法添加觀察者,那么觀察者會一直收到數據變化的回調通知;
如果通過observe()
方法添加,那么觀察者只會在LifecycleOwner處於STARTED和RESUMED即active狀態才會收到。
其中observe()
方法內部使用了LifecycleBoundObserver類,observeForever()
方法內部則使用了AlwaysActiveObserver類,它們都是抽象類ObserverWrapper的具體實現類。
所以,我們先來看一下這個抽象類:
private abstract class ObserverWrapper { final Observer<T> mObserver; boolean mActive; int mLastVersion = START_VERSION; ...... void activeStateChanged(boolean newActive) { //新狀態和之前狀態相同則不做任何處理 if (newActive == mActive) { return; } // 將當前狀態設置為傳入的newActive mActive = newActive; //處於active狀態的觀察者數量是否為0 boolean wasInactive = LiveData.this.mActiveCount == 0; //如果當前狀態為active狀態,則處於active狀態的觀察者數量加1,否則減1 LiveData.this.mActiveCount += mActive ? 1 : -1; //處於active狀態的觀察者個數從0變為1,回調LiveData的onActive()方法 if (wasInactive && mActive) { onActive(); } //處於active狀態的觀察者數量從1變為0,回調LiveData的onInactive()方法 if (LiveData.this.mActiveCount == 0 && !mActive) { onInactive(); } if (mActive) { dispatchingValue(this); } } }
ObserverWrapper是Observer的封裝類,在Observer的基礎上增加了 mActive 和 mLastVersion 。其中mActive 用來標識觀察者是否活躍,即它是否處於可用的生命周期內。
onActiveStateChanged()
方法定義了觀察者在活躍狀態和非活躍狀態之間轉換時的處理邏輯,如果ObserverWrapper對象處於活躍狀態,那么LiveData中的mActiveCount 計數會加一,否則會減一。緊接着,onActive()
方法會在mActiveCount為1時觸發,onInactive()
方法則會在mActiveCount為0時觸發。最后,如果ObserverWrapper對象處於活躍狀態,還會調用 dispatchingValue()
方法發送新的數據。
private void dispatchingValue(@Nullable ObserverWrapper initiator) { //如果mDispatchingValue為true,則將mDispatchInvalidated設為true並直接返回 if (mDispatchingValue) { mDispatchInvalidated = true; return; } mDispatchingValue = true; do { mDispatchInvalidated = false; if (initiator != null) { considerNotify(initiator); initiator = null; } else { for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { considerNotify(iterator.next().getValue()); if (mDispatchInvalidated) { break; } } } } while (mDispatchInvalidated); mDispatchingValue = false; }
其中,mDispatchingValue和mDispatchInvalidated變量是為了防止重復分發。該方法會循環遍歷mObservers 這個集合,並通過調用considerNotify()
方法為每一個處於活躍狀態且數據未更新的觀察者發送數據。
private void considerNotify(ObserverWrapper observer) { if (!observer.mActive) { return; } if (!observer.shouldBeActive()) { observer.activeStateChanged(false); return; } if (observer.mLastVersion >= mVersion) { return; } observer.mLastVersion = mVersion; observer.mObserver.onChanged((T) mData); }
現在我們再來分析LifecycleBoundObserver類和AlwaysActiveObserver類。我們先看LifecycleBoundObserver:
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver { @NonNull final LifecycleOwner mOwner; LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) { super(observer); mOwner = owner; } //判斷是否處於active狀態 @Override boolean shouldBeActive() { return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED); } //當LifecycleOwner生命周期發生變化時會回調該方法 @Override public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) { //如果當前處於DESTROYED狀態,則會自動移除觀察者 if (mOwner.getLifecycle().getCurrentState() == DESTROYED) { removeObserver(mObserver); return; } //調用ObserverWrapper的activeStateChanged()方法,將當前是否處於active狀態的判斷結果作為參數傳入 activeStateChanged(shouldBeActive()); } @Override boolean isAttachedTo(LifecycleOwner owner) { return mOwner == owner; } @Override void detachObserver() { mOwner.getLifecycle().removeObserver(this); } }
可以看出,LifecycleBoundObserver 把 ObserverWrapper 和 Lifecycle 結合在了一起。因此LiveData就可以獲取到觀察者的生命周期,當觀察者的生命周期可用時,LiveData 會把數據發送給觀察者,而當觀察者生命周期不可用的時,即owner.getLifecycle().getCurrentState() == DESTROYED
,LiveData 就選擇不發送並且自動解綁,防止內存泄漏。
AlwaysActiveObserver顧名思義觀察者的生命周期一直可用,所以它和LifecycleOwner的生命周期無關,當數據改變時不管LifecycleOwner處於什么狀態都會收到回調通知,除非手動將這個觀察者移除。從AlwaysActiveObserver的源碼也可以看出,它通過shouldBeActive()
方法將自己的生命周期設為一直可用,LiveData的observeForever()
方法內部使用的就是AlwaysActiveObserver。
private class AlwaysActiveObserver extends ObserverWrapper { AlwaysActiveObserver(Observer<T> observer) { super(observer); } @Override boolean shouldBeActive() { return true; } }
3.2 LiveData中的數據如何更新?
那么怎么改變LiveData中持有的數據呢?LiveData提供了兩種方法——postValue()
和setValue()
:
@MainThread protected void setValue(T value) { //判斷當前線程是否是主線程,不是主線程就拋出異常 assertMainThread("setValue"); //版本更新 mVersion++; //改變LiveData持有的數據 mData = value; //將新的數據分發給訂閱該LiveData所有的觀察者們 dispatchingValue(null); } protected void postValue(T value) { boolean postTask; synchronized (mDataLock) { postTask = mPendingData == NOT_SET; mPendingData = value; } if (!postTask) return; //在主線程中執行mPostValueRunnable中的內容 ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); } private final Runnable mPostValueRunnable = new Runnable() { @Override public void run() { Object newValue; synchronized (mDataLock) { newValue = mPendingData; mPendingData = NOT_SET; } setValue((T) newValue); } };
它們的區別是setValue()
方法要在主線程中調用,而postValue()
方法既可在主線程也可在子線程中調用。這是因為postValue()
方法則通過ArchTaskExecutor將mPostValueRunnable運行在主線程,而在mPostValueRunnable中最終會調用setValue()
方法來實現改變LiveData存儲的數據。
但是我們發現LiveData並沒有將這兩個方法對外公開,好在我們可以通過LiveData的子類MutableLiveData實現數據的修改,其源碼如下:
public class MutableLiveData<T> extends LiveData<T> { @Override public void postValue(T value) { super.postValue(value); } @Override public void setValue(T value) { super.setValue(value); } }
LiveData還有一個子類MediatorLiveData,它可以看成多個LiveData的代理。它定義了一個內部類Source,用於封裝LiveData和Observer,這樣如果多個LiveData被添加到MediatorLiveData中,那么任何一個LiveData數據發生變化時,MediatorLiveData的觀察者都會收到通知。Source的源碼如下:
private static class Source<V> implements Observer<V> { final LiveData<V> mLiveData; final Observer<V> mObserver; int mVersion = START_VERSION; Source(LiveData<V> liveData, final Observer<V> observer) { mLiveData = liveData; mObserver = observer; } void plug() { mLiveData.observeForever(this); } void unplug() { mLiveData.removeObserver(this); } @Override public void onChanged(@Nullable V v) { if (mVersion != mLiveData.getVersion()) { mVersion = mLiveData.getVersion(); mObserver.onChanged(v); } } }
通過一個簡單的應用場景可以更加清楚地說明MediatorLiveData的作用。例如,一個Activity界面的UI數據依賴於網絡數據源和數據庫數據,因此會有兩個LiveData。使用MediatorLiveData將兩個LiveData合並后,Activity只需觀察一個MediatorLiveData即可。無論何時,只要任何一個LiveData數據源發生變化,都會通知Activity的UI進行更新。