LiveData是Jetpack里一個(gè)十分常用的組件,它是一個(gè)可以被觀察的數(shù)據(jù)源。能夠感知 Activity等的生命周期,在onStart或者onResume的時(shí)候才會(huì)回調(diào)監(jiān)聽。
這里舉個(gè)簡單的例子,我們?cè)贏ctivity中可以使用DataSource的observe方法去監(jiān)聽內(nèi)部數(shù)據(jù)的改變,直接修改TextView,因?yàn)檫@個(gè)方法是回調(diào)在主線程的。而且可以看到DataSource里面是沒有解注冊(cè)的方法的,原因是LiveData會(huì)幫我們自動(dòng)在LifecycleOwner的onDestory的時(shí)候解注冊(cè):
class DataSource {
private val liveData = MutableLiveData<Int>()
fun observe(owner: LifecycleOwner, observer: Observer<Int>) {
liveData.observe(owner, observer)
}
fun loadData() {
Thread(Runnable {
// 加載數(shù)據(jù)
//liveData.value = 123 // 主線程中
liveData.postValue(123) // 子線程中
}).start()
}
}
// Activity中監(jiān)聽
dataSource.observe(this, Observer {data->
textView.text = "data = ${data}"
})
知道用法之后我們來看看原理,瞧一瞧它是如何實(shí)現(xiàn)的。
注冊(cè)監(jiān)聽
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
new SafeIterableMap<>();
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
// 判斷主線程
assertMainThread("observe");
// 判斷是否已經(jīng)DESTROYED
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
return;
}
// 創(chuàng)建LifecycleBoundObserver
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// 判斷是否已經(jīng)添加過監(jiān)聽,如果沒有就丟入mObservers這個(gè)map中保存
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;
}
// 向Lifecycle注冊(cè)監(jiān)聽
owner.getLifecycle().addObserver(wrapper);
}
首先是注冊(cè)監(jiān)聽,這個(gè)代碼十分簡單,具體可以看我寫的注釋。它最核心的功能就是最后的向Lifecycle注冊(cè)監(jiān)聽。
數(shù)據(jù)更新與通知
注冊(cè)完監(jiān)聽之后我們看看數(shù)據(jù)的更新部分,如果在主線程的話直接調(diào)用LiveData的setValue方法即可更新數(shù)據(jù):
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
這個(gè)方法邏輯也很清晰,總共四行就做了四件事情:
- 判斷主線程
- 更新數(shù)據(jù)版本
- 更新數(shù)據(jù)
- 分發(fā)更新事件
dispatchingValue里面判斷傳入的initiator是否為空,如果不為空則只通知該observer,否則通知所有的observer:
void dispatchingValue(@Nullable ObserverWrapper initiator) {
...
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
...
}
}
...
}
considerNotify方法也比較易懂,就是判斷Observer是否已經(jīng)激活,如果沒有激活就返回。如果激活了再判斷observer是否已經(jīng)接收到最后一次修改數(shù)據(jù)的事件(反正Activity反復(fù)切換的時(shí)候重復(fù)通知),如果沒有就調(diào)用onChanged方法通知。
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);
}
這里的Active判斷其實(shí)判斷的observer的owner的是否至少是onStart的:
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
生命周期感知
也就是說如果Activity是在后臺(tái)的,那么setValue的時(shí)候就不會(huì)去通知observer,這就是LiveData的生命周期感知機(jī)制。那么這個(gè)消息是否就丟失了呢?當(dāng)然不是。
還記得observe方法里面向Lifecycle注冊(cè)了監(jiān)聽嗎:
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
...
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
...
owner.getLifecycle().addObserver(wrapper);
}
在Activity走到各個(gè)生命周期的時(shí)候LifeCycle就會(huì)回調(diào)LifecycleBoundObserver的onStateChanged方法:
public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
在這里面做兩件事情:
- 判斷owner是否已經(jīng)destroy了,如果是就自動(dòng)解除監(jiān)聽
- 如果沒有destroy就修改激活狀態(tài)
如果是start或者resume的activeStateChanged里面就會(huì)進(jìn)行事件方法:
void activeStateChanged(boolean newActive) {
...
mActive = newActive;
...
if (mActive) {
dispatchingValue(this);
}
}
dispatchingValue方法上面講過,在這里會(huì)調(diào)用considerNotify去單獨(dú)分發(fā)給initiator。:
void dispatchingValue(@Nullable ObserverWrapper initiator) {
...
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
...
}
}
...
}
于是observer就能監(jiān)聽到onStart之前發(fā)送的消息了。
粘性事件
LiveData的事件都是粘性事件,什么是粘性事件呢?簡單來講就是注冊(cè)的監(jiān)聽可以接收到注冊(cè)之前的事件:
class DataSource {
private val liveData = MutableLiveData<Int>()
fun observe(owner: LifecycleOwner, observer: Observer<Int>) {
liveData.observe(owner, observer)
}
fun loadData() {
liveData.value = 123
}
}
// Activity
override fun onResume() {
super.onResume()
// 先發(fā)送
dataSource.loadData()
// 再注冊(cè)
dataSource.observe(this, Observer { data ->
Log.d("testtest", "data = ${data}")
})
}
這個(gè)其實(shí)結(jié)合上面的更新流程,去到considerNotify里面只要mLastVersion小于LiverData.mVersion就會(huì)被通知
private void considerNotify(ObserverWrapper observer) {
...
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
而在創(chuàng)建ObserverWrapper的時(shí)候mLastVersion初始化是-1:
public abstract class LiveData<T> {
...
static final int START_VERSION = -1;
...
private abstract class ObserverWrapper {
...
int mLastVersion = START_VERSION;
...
}
...
}
于是注冊(cè)的時(shí)候就會(huì)直接通知到LiveData之前設(shè)置的數(shù)據(jù)了。
實(shí)現(xiàn)非粘性事件
如果我們不想要這個(gè)粘性事件要怎么做呢?從根本原因上來講是因?yàn)閛bserve創(chuàng)建ObserverWrapper的時(shí)候mLastVersion直接設(shè)置成了-1,所以在分發(fā)的時(shí)候肯定會(huì)被分發(fā)一次。也就是說只要我們?cè)趧?chuàng)建的時(shí)候?qū)LastVersion設(shè)置成當(dāng)前LiveData的mVersion就能避免了。
但是無論mLastVersion還是mVersion都是沒有對(duì)外公開的,所以很容易想到繼承LiveData在observe的時(shí)候反射去修改mLastVersion。但是反射的代碼比較惡心,我就不貼出來了。我這里再提供另外一種思路:
class MyLiveData<T> : LiveData<T>() {
var version = -1
public override fun setValue(value: T) {
version++
super.setValue(value)
}
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
super.observe(owner, ObserverWrapper(observer, version))
}
private inner class ObserverWrapper<T>(
private val observer: Observer<in T>,
private var version: Int
) :
Observer<T> {
override fun onChanged(t: T) {
if (this.version < this@MyLiveData.version) {
observer.onChanged(t)
}
this.version = this@MyLiveData.version
}
}
}
代碼很簡單,我們自己使用裝飾器模式再包裝了一層維護(hù)了LiveData的version和Observer的version進(jìn)行判斷。
postValue
在上面我們看到setValue是會(huì)判斷主線程的:
protected void setValue(T value) {
assertMainThread("setValue");
...
}
如果我們?cè)谧泳€程里面想要修改數(shù)據(jù)需要使用postValue:
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
它的原理其實(shí)很簡單,將value保存到mPendingData,然后用postToMainThread(最底層其實(shí)是Handler.post)將mPostValueRunnable丟到主線程執(zhí)行setValue(mPendingData)方法.
而且在postValue會(huì)判斷之前是否有設(shè)置過mPendingData,如果有代表已經(jīng)post過Runnable,于是就不再post第二個(gè),也就是說最多只有一個(gè)Runnable會(huì)被post。
于是這就有個(gè)問題了,就是在子線程中多次postValue,只有最后一個(gè)value會(huì)在主線程中最終設(shè)置。
但其實(shí)這個(gè)也并不是什么問題,大多數(shù)情況下主線程其實(shí)并不關(guān)心數(shù)據(jù)是如何一步步更新的,只關(guān)心最終的結(jié)果。
observeForever
observe注冊(cè)的觀察者都是生命周期感知的,如果不是start活著resume狀態(tài)的話是不能立馬接收到消息的。如果我們需要非生命周期感知的話可以使用observeForever方法,里面創(chuàng)建的是AlwaysActiveObserver而不是observe里看到的LifecycleBoundObserver:
public void observeForever(@NonNull Observer<? super T> observer) {
...
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
...
}
它的特點(diǎn)在于shouldBeActive永遠(yuǎn)是true:
private class AlwaysActiveObserver extends ObserverWrapper {
...
@Override
boolean shouldBeActive() {
return true;
}
}
這就意味著considerNotify里面肯定會(huì)繼續(xù)往下走到version判斷那里,不會(huì)因?yàn)樯芷诙崆敖Y(jié)束:
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) { // AlwaysActiveObserver永遠(yuǎn)為true
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}