LiveData 原始碼分析
前言
最近的專案重構中加入LiveData框架,並且小碼的T-MVVM 也是用了LiveData框架,好不好用你試試就知道(小碼口頭禪),對於LiveData使用的時候並未做太多的理解,於是乎翻了翻LiveData原始碼,在此做下筆記,
什麼是LiveData
LiveData是一個數據持有類。它具有以下特點:
- 資料可以被觀察者訂閱;
- 能夠感知元件(Fragment、Activity、Service)的生命週期;
- 只有在元件出於啟用狀態才會通知觀察者有資料更新;
LiveData能為我們做什麼
- 能夠保證資料和UI統一,LiveData採用了觀察者模式,LiveData是被觀察者,當資料有變化時會通知UI。
- 減少記憶體洩漏,LiveData能夠感知到元件的生命週期,當元件處於DESTROYED狀態時,觀察者物件會被清除,當Activity停止時不會導致Crash,因為元件處於非啟用狀態時,不會收到LiveData中資料變化的通知。
- 不需要額外的手動處理來響應生命週期的變化,因為LiveData能夠感知元件的生命週期,所以就完全不需要在程式碼中告訴LiveData元件的生命週期狀態。
-
元件和資料相關的內容能實時更新,元件在前臺的時候能夠實時收到資料改變的通知,當元件從後臺到前臺來時,LiveData能夠將最新的資料通知元件,因此保證了元件中和資料相關的內容能夠實時更新。
若果橫豎屏切換(configuration change)時,不需要額外的處理來儲存資料,當螢幕方向變化時,元件會被recreate,然而系統並不能保證你的資料能夠被恢復的。當我們採用LiveData儲存資料時,因為資料和元件分離了。當元件被recreate,資料還是存在LiveData中,並不會被銷燬。 - 資源共享.
接下來先從使用玩起,
-
使用LiveData物件,
-
繼承LiveData類,如MutableLiveData,
發起資料通知2種方式:postValue和setValue:
private MutableLiveData<String> mData=new MutableLiveData(); mBookData.postValue("Hello LiveData"); // mBookData.setValue("Hello LiveData");
此處postValue和setValue的區別,下文會提,
註冊觀察者並監聽資料變化:
mData.observe(this, new Observer<String>() { @Override public void onChanged(@Nullable String str) { Toast.makeText(this, str, Toast.LENGTH_SHORT).show(); } });
使用非常簡單,僅此而已
通過observe方法註冊觀察者,哪咋們就看看observe裡面具體幹了什麼,原始碼165行走起,
//註冊觀察 @MainThread public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) { if (owner.getLifecycle().getCurrentState() == DESTROYED) { // ignore return; } LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); 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); }
observe方法接收2個引數,一個是具有生命週期的LifecycleOwner,另一個是觀察者Observer<T> ,首先判斷LifecycleOwner當前的生命週期是否為Destroyed,如果是則直接 return;如果不等於Destroyed,接下來往下看, 此處new了一個內部類LifecycleBoundObserver物件並且構造方法傳入了具有生命週期的LifecycleOwner和觀察者,這是個什麼鬼,看看他的具體方法,LifecycleBoundObserver繼承自ObserverWrapper,並實現GenericLifecycleObserver,而GenericLifecycleObserver繼承了LifecycleObserver介面。由此可以看出LifecycleBoundObserver類就是把Observer和生命週期關聯起來,ok,那我們先看看LifecycleBoundObserver方法,原始碼349行走起,
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver { @NonNull final LifecycleOwner mOwner; LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) { super(observer); mOwner = owner; } @Override boolean shouldBeActive() { return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED); } @Override public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) { if (mOwner.getLifecycle().getCurrentState() == DESTROYED) { removeObserver(mObserver); return; } activeStateChanged(shouldBeActive()); } @Override boolean isAttachedTo(LifecycleOwner owner) { return mOwner == owner; } @Override void detachObserver() { mOwner.getLifecycle().removeObserver(this); } }
此方法中,我們先看onStateChanged()方法,當生命週期變化時會回撥,如果getCurrentState() == DESTROYED則removeObserver,反之則呼叫父類ObserverWrapper的activeStateChanged()方法,原始碼382行走起,
private abstract class ObserverWrapper { final Observer<T> mObserver; boolean mActive; int mLastVersion = START_VERSION; ObserverWrapper(Observer<T> observer) { mObserver = observer; } abstract boolean shouldBeActive(); boolean isAttachedTo(LifecycleOwner owner) { return false; } void detachObserver() { } 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); } } }
activeStateChanged()是幹嘛的,首先判斷activeState新舊狀態是否相同,不同則把新的狀態賦給mActive,是生命週期狀態處於ACTIVE情況下的邏輯處理。如果新的狀態和舊的狀態相同則直接返回。這裡有個常量LiveData.this.mActiveCount,看註釋可以理解為觀察者處於活動狀態
個數,往下看 if (wasInactive && mActive)如果mActiveCount=0並且mActive為true,即觀察者處於活動狀態
個數從0變為1個則呼叫onActive(); 觀察者處於活動狀態
個數從1變為0時則呼叫onInactive()。然而onActive(),onInactive()並沒有任何實現程式碼。好了,接下來繼續往下看dispatchingValue(this);應該就是資料變化訊息排程。原始碼112行走起,
private 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<T>, ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { considerNotify(iterator.next().getValue()); if (mDispatchInvalidated) { break; } } } } while (mDispatchInvalidated); mDispatchingValue = false; }
前面的幾行if 判斷姑且先不看,先看從if(initiator != null)開始看,如果initiator!= null呼叫considerNotify(initiator)方法;原始碼91行走起,
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); }
看見沒有最後一行程式碼 observer.mObserver.onChanged((T) mData);Observer的資料變化回撥;好了我們再回過頭看看initiator == null的邏輯,
for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { considerNotify(iterator.next().getValue()); if (mDispatchInvalidated) { break; } }
如果initiator == null則會通過迭代器mObservers遍歷獲取ObserverWrapper,最終還是呼叫considerNotify方法;既然有取ObserverWrapper,咋們再看看在哪兒存的,在原始碼171行:
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);
mObservers.putIfAbsent(observer, wrapper)存入容器中,mObservers.putIfAbsent這個新增資料的方式貌似很少見,於是乎在看看mObservers是個什麼資料容器,成員變數中:
private SafeIterableMap<Observer<T>, ObserverWrapper> mObservers = new SafeIterableMap<>();
這是個什麼鬼,貌似以前很少見,查閱資料發現:
SafeIterableMap有以下特性:
1;支援鍵值對儲存,用連結串列實現,模擬成Map的介面
2:支援在遍歷的過程中刪除任意元素,不會觸發ConcurrentModifiedException
3:非執行緒安全
感興趣的可自行查閱,此處不再詳細介紹,
最後addObserver添加註冊。
下面在看看資料發起通知的邏輯,資料發起通知有2中方式:
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); } }
setValue和postValue2中方式,我們先看看setValue程式碼:
@MainThread protected void setValue(T value) { assertMainThread("setValue"); mVersion++; mData = value; dispatchingValue(null); } private static void assertMainThread(String methodName) { if (!ArchTaskExecutor.getInstance().isMainThread()) { throw new IllegalStateException("Cannot invoke " + methodName + " on a background" + " thread"); } }
setValue第一行程式碼 assertMainThread("setValue");則是判斷是否在主執行緒,所以貌似setValue方式必須在主執行緒中執行,如果非主執行緒則丟擲異常。
再看看postValue:
protected void postValue(T value) { boolean postTask; synchronized (mDataLock) { postTask = mPendingData == NOT_SET; mPendingData = value; } if (!postTask) { return; } ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); }
則postValue呼叫postToMainThread方法,最終還是用過setValue方式:
private final Runnable mPostValueRunnable = new Runnable() { @Override public void run() { Object newValue; synchronized (mDataLock) { newValue = mPendingData; mPendingData = NOT_SET; } //noinspection unchecked setValue((T) newValue); } };
因此最終明白為什麼setValue方法只能在主執行緒中呼叫,postValue可以在任何執行緒中呼叫,如果是在後臺子執行緒中更新LiveData的值,必須呼叫postValue。
至此大概明白了LiveData是幹嘛的 ,怎麼幹的,總的來說還是很好用的,於是乎就有個小小的想法,平時用Eventbus,RxBus什麼的,貌似感覺LiveData也可以實現事件匯流排,既然有了想法,那就幹唄,
/** * 事件匯流排 * * @author:tqzhang on 18/9/11 17:22 */ public class LiveBus { private static volatile LiveBus instance; private final Map<Object, MutableLiveData<Object>> mLiveBus; private LiveBus() { mLiveBus = new HashMap<>(); } public static LiveBus getDefault() { if (instance == null) { synchronized (LiveBus.class) { if (instance == null) { instance = new LiveBus(); } } } return instance; } /** * * subscriber 註冊時間 key */ public <T> MutableLiveData<T> subscribe(Object subscriber, Class<T> tMutableLiveData) { checkNotNull(subscriber); checkNotNull(tMutableLiveData); if (!mLiveBus.containsKey(subscriber)) { mLiveBus.put(subscriber, new MutableLiveData<>()); } return (MutableLiveData<T>) mLiveBus.get(subscriber); } }
簡單的50行程式碼實現類似Eventbus,RxBus的功能,小碼親測了,挺好使的。
//發起通知 LiveBus.getDefault().subscribe("livedata",String.class).postValue("hello LiveData"); //註冊觀察 LiveBus.getDefault().subscribe("livedata",String.class).observe(this, new Observer<String>() { @Override public void onChanged(@Nullable String s) { Toast.makeText(activity, s, Toast.LENGTH_SHORT).show(); } });