Android Jetpack組件庫LiveData源碼深入探究
Android Jetpack之ViewModel、LiveData
Android Jetpack之DataBinding+ViewModel+LiveData+Room
前言
Jetpack是一個由多個技術庫組成的套件,可幫助開發(fā)者遵循最佳做法,減少樣板代碼并編寫可在各種Android版本和設備中一致運行的代碼,讓開發(fā)者精力集中編寫重要的代碼。
一、LiveData
LiveData 是一種持有可被觀察的數(shù)據(jù)存儲類。和其他可被觀察的類不同的是LiveData 可以在 Activity ,fragment 或者 service 生命周期發(fā)生改變時通知更新。LiveData 已經(jīng)是必不可少的一環(huán)了,例如 MVVM 以及 MVI 開發(fā)模式中,都用到了 LiveData。
(注意??源碼是Java代碼)
LIveData 的優(yōu)勢:
- 確保界面符合數(shù)據(jù)狀態(tài):數(shù)據(jù)發(fā)生變化時,就會通知觀察者。我們可以再觀察者回調(diào)中更新界面,這樣就無需在數(shù)據(jù)改變后手動更新界面了。
- 沒有內(nèi)存泄漏,因為關聯(lián)了生命周期,頁面銷毀后會進行自我清理。
- 不會因為Activity 停止而導致崩潰,頁面處于非活躍狀態(tài)時,他不會接收到任何 LiveData 事件。
- 共享資源,可以使用單例模式擴展 LiveData 對象,以便在應用中共享他們。
- 屏幕翻轉(zhuǎn)數(shù)據(jù)狀態(tài)保留
- 不再需要手動處理生命周期
- 數(shù)據(jù)始終保持最新狀態(tài)
二、使用案例
LiveData 是一種可用于任何數(shù)據(jù)的封裝容器,通常 LiveData 存儲在 ViewModel 對象中。
class JokesDetailViewModel : ViewModel() { //創(chuàng)建 LiveData private val _state by lazy { MutableLiveData<JokesUIState>() } val state : LiveData<JokesUIState> = _state private fun loadChildComment(page: Int, commentId: Int, parentPos: Int, curPos: Int) { viewModelScope.launch { launchHttp { jokesApi.jokesCommentListItem(commentId, page)//請求數(shù)據(jù) }.toData { //通知觀察者 _state.value = JokesUIState.LoadMoreChildComment(it.data, parentPos, curPos) } } } } //觀察 LiveData viewModel.state.observe(this, Observer { //更新 UI })
三、LiveData 實現(xiàn)原理
- Observer:觀察者接口;
- LiveData:發(fā)送已經(jīng)添加觀察的邏輯都在其中;
- ObserverWrapper:抽象的觀察者包裝類;
- LifecycleBoundleObserver:繼承 ObserverWrapper;
- LifecycleEventObserver,生命周期相關回調(diào);
observe(this,Observer{})
@MainThread public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { //如果已經(jīng)銷毀,直接退出 if (owner.getLifecycle().getCurrentState() == DESTROYED) { return; } //包裝類(下面源碼) LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer); //判斷是否已添加 ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); if (existing != null && !existing.isAttachedTo(owner)) { //.... } //之前添加過 if (existing != null) { return; } //注冊 lifecycle,生命周期改變時會回調(diào) owner.getLifecycle().addObserver(wrapper); }
LifecycleBoundObserver(owner, observer)
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver { @NonNull final LifecycleOwner mOwner; LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) { super(observer); mOwner = owner; } //當前狀態(tài)大于或者等于 STARTED 返回 true @Override boolean shouldBeActive() { return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED); } //生命周期相關回調(diào) @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState(); //如果已經(jīng)銷毀,移除觀察者 if (currentState == DESTROYED) { removeObserver(mObserver); return; } Lifecycle.State prevState = null; //循環(huán)更新狀態(tài) while (prevState != currentState) { prevState = currentState; //修改活躍狀態(tài) activeStateChanged(shouldBeActive()); currentState = mOwner.getLifecycle().getCurrentState(); } } @Override boolean isAttachedTo(LifecycleOwner owner) { return mOwner == owner; } @Override void detachObserver() { mOwner.getLifecycle().removeObserver(this); } }
- 繼承 ObserverWrapper 的包裝類--activeStateChanged(..)方法。
- 實現(xiàn)LifecycleEventObserver 接口--onStateChanged(..)方法。
ObserverWrapper.activeStateChanged()
void activeStateChanged(boolean newActive) { //如果等于之前狀態(tài) if (newActive == mActive) { return; } mActive = newActive; //活躍 +1,不活躍 -1 (下面有源碼) changeActiveCounter(mActive ? 1 : -1); //如果狀態(tài)變成了活躍狀態(tài),直接調(diào)用 dispatchingValue,傳入當前的觀察者 if (mActive) { dispatchingValue(this); //(下面有源碼) } } //修改活躍數(shù)量 void changeActiveCounter(int change) { int previousActiveCount = mActiveCount;//之前活躍的數(shù)量 mActiveCount += change;//總活躍數(shù)量 if (mChangingActiveState) {//如果正在更改,退出 return; } mChangingActiveState = true;//更改中 try { while (previousActiveCount != mActiveCount) { boolean needToCallActive = previousActiveCount == 0 && mActiveCount > 0; boolean needToCallInactive = previousActiveCount > 0 && mActiveCount == 0; previousActiveCount = mActiveCount; //如果當前是第一個激活的,調(diào)用 onActive if (needToCallActive) { onActive();//當活動的觀察者從0 變成 1的時候調(diào)用 //如果沒有激活的為 0 ,調(diào)用 onInactive } else if (needToCallInactive) { onInactive();//活躍的觀察者變成 0 時調(diào)用 } } } finally { mChangingActiveState = false; } } //分發(fā)數(shù)據(jù) void dispatchingValue(@Nullable ObserverWrapper initiator) { if (mDispatchingValue) { mDispatchInvalidated = true; return; //如果正在分發(fā),退出 } mDispatchingValue = true; do { mDispatchInvalidated = false; //如果觀察者不為空 if (initiator != null) { considerNotify(initiator);//對數(shù)據(jù)進行派發(fā),通知觀察者 initiator = null; } else { //如果為空,遍歷所有的觀察者,將數(shù)據(jù)發(fā)送給所有觀察者 for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { considerNotify(iterator.next().getValue()); if (mDispatchInvalidated) { break; } } } } while (mDispatchInvalidated); mDispatchingValue = false; } //數(shù)據(jù)進行派發(fā),通知觀察者 private void considerNotify(ObserverWrapper observer) { if (!observer.mActive) { return; } //再次進行判斷,如果不活躍,則會更新狀態(tài),然后退出 if (!observer.shouldBeActive()) { observer.activeStateChanged(false); return; } //觀察者版本是否低于當前的版本 //初始值 mLastVersion 為 -1,mVersion 為 0 //小于等于表示沒有需要更新的數(shù)據(jù) if (observer.mLastVersion >= mVersion) { return; } //更新版本 observer.mLastVersion = mVersion; //通知觀察者 observer.mObserver.onChanged((T) mData); }
梳理流程:
1、通過 observe 添加一個觀察者,這個觀察者會被 LifecycleBoundObserver 進行一個封裝,LifecycleBoundObserver繼承 ObserverWrapper,并且實現(xiàn)了 LifecycleEventObserver。之后就會將觀察添加到 Observers 中,最后注冊頁面生命周期的 observer。
2、當生命周期發(fā)生變化后,就會回調(diào)到 LifecycleBoundObserve 中的 onStateChanged 方法中。如果生命周期是銷毀的,就會移除觀察者,如果不是就會循環(huán)更新當前狀態(tài)。
3、在更新狀態(tài)的時候就會判斷是否為活躍狀態(tài),如果是活躍狀態(tài)就會進行分發(fā),分發(fā)的時候如果觀察者為 null ,就會遍歷所有的觀察者進行分發(fā),否則就分發(fā)傳入的觀察者。
4、最后會再次判斷活躍狀態(tài),已經(jīng)判斷觀察者版本是否低于當前版本,如果都滿足,就會更新觀察者。
onActive 與 onInactive
如果觀察者的生命周期處于 STARTED 或者 RESUMED 狀態(tài),LiveData 就會認為觀察者處于活躍狀態(tài)。
例如,下載數(shù)據(jù)需要在活躍狀態(tài)下進行,或者需要實時的監(jiān)聽后臺數(shù)據(jù),就可以重新下面方法,并完成對應邏輯。
class StockLiveData(url: String) : LiveData<String>() { private val downloadManager = DownloadManager(url) override fun onActive() { if(!downloadManager.isStart()){ downloadManager.start() } } override fun onInactive() { downloadManager.stop() } }
當具有活躍的觀察者時,就會調(diào)用 onActive 方法。
當沒有任何活躍的觀察者時,就會調(diào)用 onInactive 方法。
當然這只是我想到的場景,開發(fā)中可以根據(jù)不同的業(yè)務場景做出不同的判斷。
四、LiveData 相關源碼
MutableLiveData
由于 LiveData 的發(fā)送數(shù)據(jù)方法是 protected 修飾私有受保護的,所以不能直接調(diào)用。因此使用MutableLiveData 繼承 LiveData 將發(fā)送數(shù)據(jù)的方法改為了 public。
public class MutableLiveData<T> extends LiveData<T> { /** * Creates a MutableLiveData initialized with the given {@code value}. */ public MutableLiveData(T value) { super(value); } /** * Creates a MutableLiveData with no value assigned to it. */ public MutableLiveData() { super(); } @Override public void postValue(T value) { super.postValue(value); } @Override public void setValue(T value) { super.setValue(value); } }
Transformations.map()
在數(shù)據(jù)分發(fā)給觀察者之前對其中存儲的值進行更改,返回一個新的 LiveData,可以使用此方法。
val strLiveData = MutableLiveData<String>() val strLengthLiveData = Transformations.map(strLiveData) { it.length } strLiveData.observe(this) { Log.e("---345---> str:", "$it"); } strLengthLiveData.observe(this) { Log.e("---345---> strLength:", "$it"); } strLiveData.value = "hello word" E/---345---> str:: hello word E/---345---> strLength:: 10
Transformations.switchMap()
對上面的做了個判斷,根據(jù)不同的需求返回不同的 LiveData。也可以通過 id 去判斷,返回對應的 livedata 即可。
val idLiveData = MutableLiveData<Int>() val userLiveData = Transformations.switchMap(idLiveData) { id-> getUser(id) }
合并多個 LiveData
val live1 = MutableLiveData<String>() val live2 = MutableLiveData<String>() val mediator = MediatorLiveData<String>() mediator.addSource(live1) { mediator.value = it Log.e("---345---> live1", "$it"); } mediator.addSource(live2){ mediator.value = it Log.e("---345---> live2", "$it"); } mediator.observe(this, Observer { Log.e("---345---> mediator", "$it"); }) live1.value = "hello" E/---345---> mediator: hello E/---345---> live1: hello
通過 MediatorLiveData 將兩個 MutableLiveData 合并到一起,這樣當任何一個發(fā)生變化,MediatorLiveData 都可以感知到。
五、LiveData分發(fā)問題
數(shù)據(jù)粘性事件
例如再沒有觀察者的時候發(fā)送數(shù)據(jù),此時 mVersion +1,等到真正添加了觀察者后,生命周期也是活躍的,那么就會將這個數(shù)據(jù)重新分發(fā)到觀察者。所以說發(fā)送數(shù)據(jù)這個操作是粘性的。
如果需要去除粘性事件,可以在添加完 observe 后去通過反射修改 mVersion 和 觀察者包裝類中的 mLastVersion 的值,將 mVersion 賦值給 mLastVersion 即可去掉粘性事件。
數(shù)據(jù)倒灌現(xiàn)象
一般情況下,LiveData 都是存放在 ViewModel 中的,當Activity重建的時候,觀察者會被 remove 掉,重建后會添加一個新的觀察者,添加后新的觀察者版本號就是 -1,所以就會出現(xiàn)數(shù)據(jù)再次被接收到。
這種解決方式和上面一樣,反射修改版本號就可以解決。非活躍狀態(tài)的觀察者轉(zhuǎn)為活躍狀態(tài)后,只能接收到最后一次發(fā)送的數(shù)據(jù)。一般情況下我們都需要的是最新數(shù)據(jù),如果非要所有數(shù)據(jù),只能重寫 LiveData 了。
到此這篇關于Android Jetpack組件庫LiveData源碼深入探究的文章就介紹到這了,更多相關Android Jetpack LiveData內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- Android?Jetpack?組件LiveData源碼解析
- Android Jetpack 狠活Lifecycles與LiveData使用詳解
- Android Jetpack組件支持庫DataBinding與ViewModel與LiveData及Room詳解
- Android開發(fā)Jetpack組件ViewModel與LiveData使用講解
- Android開發(fā)Jetpack組件LiveData使用講解
- Android?Jetpack庫剖析之LiveData組件篇
- 詳解Android JetPack之LiveData的工作原理
- Android Jetpack組件中LiveData的優(yōu)劣
相關文章
Android使用Jetpack WindowManager開發(fā)可折疊設備(過程分享)
這篇文章主要介紹了Android使用Jetpack WindowManager開發(fā)可折疊設備,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-11-11Android應用開發(fā)中使用Fragment的入門學習教程
這篇文章主要介紹了Android應用開發(fā)中Fragment的入門學習教程,可以把Fragment看作為Activity基礎之上的模塊,需要的朋友可以參考下2016-02-02