結束了Lifecycle篇和ViewModel篇,終於到了相對複雜的LiveData篇了。java
最開始瞭解LiveData我是拒絕的,由於你不能上來就讓我用,立刻就用。第一我要試一下,我不原意用完之後...duang、duang都是bug....android
一點點入坑JetPack:實戰前戲NetworkBoundResource篇函數
後來用完以後,好嗨呦,感受人生已經達到了高潮...post
固然不想聽我瞎bb的,能夠直接官方文檔。若是想圖個樂,順便了解了解新技術。那歡迎光臨紅...,男賓一位,裏邊請!ui
官網:LiveData是一個可觀察的數據持有者類。與常規observable不一樣,LiveData是生命週期感知的。this
從官方文檔上咱們能夠看到倆個關鍵詞:可觀察、生命週期感知。簡單來講,Google給咱們提供了一個能夠被觀察的,而且擁有生命週期感知能力的類。那有什麼用呢?
直接上demo:
class NameViewModel : ViewModel() {
// 這裏new了一個MutableLiveData,它是LiveData的實現類,LiveData是抽象的,很明顯不能被new
val currentName: LiveData<String> by lazy {
MutableLiveData<String>()
}
}
class NameActivity : AppCompatActivity() {
private lateinit var mModel: NameViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mModel = ViewModelProviders.of(this).get(NameViewModel::class.java)
// 這個this是LifecycleOwner
mModel.currentName.observe(this, Observer { newName ->
// mNameTextView一個TextView
mNameTextView.text = newName
})
// 更新被觀察者數據,LiveData會通知觀察者
// (這裏爲了代碼簡潔直接在LiveData上post,實際這麼寫ide就直接報錯了,由於currentName返回的是LiveData,這是一個抽象類型,它裏邊的方法是protect。正常若是咱們想讓外部post返回實現類(好比:內部有一個MutableLiveData)便可。感謝評論區只出)
mModel.currentName.postValue("MDove")
}
}
複製代碼
若是看到這幾行代碼,豁然開朗,那麼能夠跳過看下面的部分。若是感受有些疑惑,不着急我們不打針不吃藥,坐下就是和你嘮...
最開始咱們先聲明瞭一個NameViewModel的ViewModel,這部份內容在ViewModel篇有所說起。內部有一個MutableLiveData的成員變量。說白了就是一個LiveData類型的String,咱們使用時是藉助LiveData的特性,但本質仍是用String。
也就是說這裏若是咱們要用一個List,那麼此時就是MutableLiveData<List<String>>()
。
Activity之中,咱們先獲取ViewModel,而後mModel.currentName.observe(...,...)
,這裏咱們就是在觀察LiveData。咱們只須要在回調中處理咱們本身的UI操做便可了。也就是demo中的mNameTextView.text = newName
。
LiveData會在每一次postValue(...)
或者value=...
時,observe()
便會回調,哪怕是null。
這裏有倆個點須要特別注意:
onPasue()
、onStop()
)時,LiveData是不會回調observe()
的,由於沒有意義。observe()
,那麼此時你調用這個LiveData的postValue(...)/value=...,是沒有任何做用。這個咱們能夠在源碼中看到。MutableLiveData:
上文我們已經見過了,沒什麼特別的,就是LiveData的實現類。就至關於List和ArrayList的關係。
MediatorLiveData:
MutableLiveData的子類,它是一個比較強大的LiveData,咱們的map()
、switchMap()
都是基於它進行實現的。 最大的特色是能夠同時監聽多個LiveData。
官網的這個小破demo,屬實太寒酸了,你卻是加點特技啊?就這中初級用法,誰能以爲好用呢!因此,若是對LiveData稍稍有點感受,那我們不要停,一塊兒決戰到天明。
初用過RxJava的小夥伴,估計會和我同樣,被各類「姿式」的操做符所正經,好比經常使用的:map、flatMap...而LiveData中一樣有這樣的操做。
一個很常見的場景:咱們經過一個惟一id去查詢這個id下的實體類,而且要同時展現兩者的數據。很簡單的業務邏輯,在LiveData中的展現是這樣的:
class NameViewModel : ViewModel() {
val userIdLiveData = MutableLiveData<Long>()
// 僞碼:當userIdLiveData發生變化時,userLiveData中的map就會調用,那麼咱們就能夠獲得罪行的id
val userLiveData: LiveData<User> = Transformations.map(userIdLiveData) { id->
// 經過id拿到User,return一個User的實例user
user
}
}
// Activity中
mModel.userLiveData.observe(this, Observer { user ->
// user變化後通知mNameTextView更新UI
mNameTextView.text = user.name
})
// 給userIdLiveData設置id爲1
mModel.userIdLiveData.postValue("1")
複製代碼
針對這個業務場景,咱們只須要監聽咱們用戶通知UI變化的LiveData(userLiveData),而後經過userIdLiveData.postValue("1")
來驅動數據的變化。
這裏可能和咱們傳統的MVP的思想並不相同,畢竟MVVM和MVP仍是有區別的,而MVVM的這種方式被稱之爲:數據驅動。
咱們直接點到Transformations.map()
中。
@MainThread
public static <X, Y> LiveData<Y> map(
@NonNull LiveData<X> source,
@NonNull final Function<X, Y> mapFunction) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(source, new Observer<X>() {
@Override
public void onChanged(@Nullable X x) {
result.setValue(mapFunction.apply(x));
}
});
return result;
}
複製代碼
很簡單,就是使用了MediatorLiveData
,而後經過一個高階函數,將高階函數返回的內容,set到LiveData上,完成map()。
既然提到了MediatorLiveData
,以及它的addSource()
的方法,那麼咱們就來看看它的源碼。
這部分沒啥意思,能夠直接跳過看3.1.四、map()源碼總結...
進入MediatorLiveData
之中,咱們會發現代碼比較少。這裏抽出倆塊比較重點的內容,咱們一同來感覺一下:
@MainThread
public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
Source<S> e = new Source<>(source, onChanged);
Source<?> existing = mSources.putIfAbsent(source, e);
if (existing != null && existing.mObserver != onChanged) {
throw new IllegalArgumentException(
"This source was already added with the different observer");
}
if (existing != null) {
return;
}
if (hasActiveObservers()) {
e.plug();
}
}
複製代碼
從這段代碼中,咱們粗略能夠獲得一個信息,這裏把咱們的LiveData和Observer封裝成了Source對象,而且這個對象,不能重複添加。
此外,Source的plug()方法,被調用。接下來咱們去看一看這個內部類Source的實現:
private static class Source<V> implements Observer<V> {
final LiveData<V> mLiveData;
final Observer<? super V> mObserver;
int mVersion = START_VERSION;
Source(LiveData<V> liveData, final Observer<? super 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);
}
}
}
複製代碼
首先Source是一個觀察者,能夠看到,咱們外部使用的Observer會以Source的成員變量的形式,添加到傳入的LiveData中。值得注意的是,這裏使用了mLiveData.observeForever(this);
。
從observeForever()
用法能夠看到,咱們並無傳遞LifecycleOwner
,所以它並不具有生命感知能力。從註釋中也可見一斑:This means that the given observer will receive all events and will never be automatically removed.
打住,打住吧。其實不必繼續看了。一句話總結:map()的原理就是基於MediatorLiveData,MediatorLiveData內部會將傳遞進來的LiveData和Observer封裝成內部類,而後放在內部維護的一個Map中。而且自動幫咱們完成observeForever
()和removeObserver()
。
switchMap()的場景能夠應用在切換LiveData上。這話怎麼解釋呢?
很常見的業務場景:好比你的業務用的是map(),map()中使用你本身寫的絡,並且LiveData運行的很良好,抽着煙喝着酒,啥事都沒有...就好比,上面map()那樣的代碼:
val userLiveData: LiveData<User> = Transformations.map(userIdLiveData) { id->
// 本身的一段邏輯
user
}
// Activity中
mViewModel.userLiveData.observe(this,Observer{->user
//更新UI
})
複製代碼
忽然有一天,這個地方數據結構、UI都沒變,惟獨變了邏輯。此時你一個同事寫好了一個方法,讓你替換一下就行了了。不過當你調用的時候忽然返現,這個方法返回一個LiveData對象!
固然此時咱們可讓UI從新observe()這個LiveData對象:
val otherLiveData:LiveData<User> = // 同事的邏輯
// Activity中從新observe()
mViewModel.otherLiveData.observe(this,Observer{->user
//更新UI
})
複製代碼
但是這樣的話,本身以前寫的東西不都白費了麼?因此此時,咱們可使用switchMap()
,咱們只須要不多的改動,就能夠設配此次需求的變更:
val userLiveData: LiveData<User> = Transformations.switchMap(userIdLiveData) { id->
// 直接把同事的代碼放在這裏便可
}
複製代碼
有了上邊map()
源碼基礎,咱們能夠很容易的看出switchMap()
的端倪:
@MainThread
public static <X, Y> LiveData<Y> switchMap(
@NonNull LiveData<X> source,
@NonNull final Function<X, LiveData<Y>> switchMapFunction) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(source, new Observer<X>() {
LiveData<Y> mSource;
@Override
public void onChanged(@Nullable X x) {
// 從Function中拿到返回的LiveData,也就是咱們新的LiveData(文章背景中同事寫的LiveData)
LiveData<Y> newLiveData = switchMapFunction.apply(x);
if (mSource == newLiveData) {
return;
}
// remove掉舊的LiveData
if (mSource != null) {
result.removeSource(mSource);
}
mSource = newLiveData;
if (mSource != null) {
// add新的LiveData
result.addSource(mSource, new Observer<Y>() {
@Override
public void onChanged(@Nullable Y y) {
// 通知LiveData發生變化
result.setValue(y);
}
});
}
}
});
return result;
}
複製代碼
咱們對比一下switchMap()
和map()
的參數類型:
很明顯一個是返回LiveData類型,一個是換一種類型。這也說明了,這倆個方法的不同之處 。
代碼解釋能夠看註釋,很直白的思路。
上述咱們看過了map()
和switchMap()
的用法。各位應該都注意到MediatorLiveData
這個類的做用。
上邊咱們一直都在操做一個LiveData,可是咱們需求很容易遇到多種狀態的變化。就像官方的demo:
LiveData liveData1 = ...;
LiveData liveData2 = ...;
MediatorLiveData liveDataMerger = new MediatorLiveData<>();
liveDataMerger.addSource(liveData1, value -> liveDataMerger.setValue(value));
liveDataMerger.addSource(liveData2, value -> liveDataMerger.setValue(value));
複製代碼
如同demo所示,咱們能夠同時add多個LiveData,根據不一樣的LiveData的變化,處理咱們不一樣的邏輯。最後經過MediatorLiveData回調到咱們的UI上。
註冊Observer
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
// 若是當前生命週期是DESTROYED,直接return
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
return;
}
// 這個包裝類,作了一件事情,在DESTROYED,移除Observer
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// 添加在已經Observer,已存在且在Attach上後直接拋異常,也就是不能重複add
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;
}
// 把Wrapper添加到LifecycleOwner上
owner.getLifecycle().addObserver(wrapper);
}
複製代碼
Observer如何被響應:
public interface Observer<T> {
/** * Called when the data is changed. * @param t The new data */
void onChanged(T t);
}
複製代碼
觸發的起點,很明顯是咱們在set/postValue的時候:
@MainThread
protected void setValue(T value) {
// 記住這個值,它是用來表示數據是否發生變化的
mVersion++;
mData = value;
dispatchingValue(null);
}
void dispatchingValue(@Nullable ObserverWrapper initiator) {
// 省略部分代碼
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
// 往裏走
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
// 省略部分代碼
}
private void considerNotify(ObserverWrapper observer) {
// 若是observer不在活動期,則直接return。也就是上述說observer不在前臺,將不會接受回調。
if (!observer.mActive) {
return;
}
// 省略部分代碼
// 很直白的version對比
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
// 回調
observer.mObserver.onChanged((T) mData);
}
複製代碼
observer.mActive
在哪被賦值?不少地方。除了一些邊界條件的賦值外,一個比較正式的賦值,ObserverWrapper
中的void activeStateChanged(boolean newActive)
方法:
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
mActive = newActive;
}
// 此方法最終會調到此方法
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
public boolean isAtLeast(@NonNull State state) {
return compareTo(state) >= 0;
}
複製代碼
很簡單,每次生命週期回調,observer.mActive
都會被賦值,而只有到Lifecycle是活動狀態是,mActive纔會true。所以只有在咱們的Activity爲前臺時咱們的LiveData
纔會被回調。
到此關於LiveData的部分就整完了,不知道各位看官是否感覺到LiveData的好用之處了呢?若是沒有,不如本身寫一寫,用身體去感覺來自LiveData的爽快~