Android JetPack組件之LiveData
簡介
和上一篇Lifecycle組件一樣,LiveData也是一個觀察者機制的東西,訂閱者訂閱LiveData後,LiveData數據發生變化,就會通知到訂閱者;
使用步驟
- 創建LiveData數據
- 加入訂閱者到LiveData中去
- 改變LiveData的值
- 觸發通知到訂閱者
僞代碼如下:
6. val myLiveData = MutableLiveData<String>()
7. myLiveData.observe(LifecycleOwner, Observer {
void onChanged(String t){
Log.i("tag", t)
}
})
8. myLiveData.postValue("new value")
9. 打印執行new value
上面代碼就是LiveData的一個簡單使用,那麼它背後的原理如何,請看下分析
實現原理
MutableLiveData
MutableLiveData類是LiveData類的子類,基本和LiveData一樣,沒有做特別的改變;當然除了MutableLiveData子類外,還有RoomTrackingLiveData類,也是LiveData的另一個實現,RoomTrackingLiveData主要是用於Database相關的操作,這裏我們只分析MutableLiveData,其代碼如下:
public class MutableLiveData<T> extends LiveData<T> {
public MutableLiveData(T value) {
super(value);
}
public MutableLiveData() {
super();
}
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
爲LiveData添加訂閱者
liveData添加訂閱者,主要是通過observer方法添加進去,需要注意的是第一個參數必須是LifecycleOwner類型,表示訂閱者自己本身也必須有一個狀態,在訂閱者死亡後LiveData就不在繼續給你同步消息了,添加observer的邏輯如下圖:
首先,在Activity裏面添加訂閱者到liveData,因爲Activity本身就實現了LifecycleOwner接口,所以第一個參數爲this即可,第二個就是Observer對象;然後就進入到LiveData類的observer裏面去,如下代碼:
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
如果添加進入的owner已經都是DESTROYED狀態,那麼久沒必要在添加進來了
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
內部封裝類,將owner和Observer參數封裝在一起
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);
}
LifecycleBoundObserver實現了LifecycleEventObserver,方便訂閱者將自己的狀態同步過來
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
訂閱者那邊如果生命狀態發生變化會把狀態通知過來
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
如果訂閱者轉頭爲DESTROYED,那就把這個訂閱者從livedata中刪除掉
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
狀態通知下去,
activeStateChanged(shouldBeActive());
}
這塊代碼主要作用是訂閱者的狀態由false變爲true的時候,要給他來一次事件發佈
void activeStateChanged(boolean newActive) {
如果狀態都一樣,那麼沒必要把數據在發佈給訂閱者
if (newActive == mActive) {
return;
}
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
/*省略部分代碼*/
如果存活就把value發送給訂閱者
if (mActive) {
dispatchingValue(this);
}
}
}
mObservers.putIfAbsent 將訂閱者添加到mObservers裏面,mObservers是SafeIterableMap類型,就是一個雙鏈表數據結構,存儲元素類型爲Entry:
public V putIfAbsent(@NonNull K key, @NonNull V v) {
Entry<K, V> entry = get(key);
if (entry != null) {
return entry.mValue;
}
put(key, v);
return null;
}
protected Entry<K, V> put(@NonNull K key, @NonNull V v) {
Entry<K, V> newEntry = new Entry<>(key, v);
mSize++;
if (mEnd == null) {
mStart = newEntry;
mEnd = mStart;
return newEntry;
}
mEnd.mNext = newEntry;
newEntry.mPrevious = mEnd;
mEnd = newEntry;
return newEntry;
}
代碼很簡單,直接看就行;
最後在observer方法最後一句owner.getLifecycle().addObserver(wrapper),也就是會把這個wrapper添加到訂閱者(Activity)那邊去,爲什麼這麼做呢?主要是添加過去後,方便Activity生命週期變化,進行狀態同步過來
更新LiveData數據
在MutableLiveData中有set和post兩種方法更新,post可以在非主線程使用,而set必須在子線程使用,我們用post來看看:
protected void postValue(T value) {
boolean postTask;
多線程處理mPendingData,所以必須加鎖
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
postTask爲false,說明mPendingData已經有值,並且正在把值分發給訂閱者;
所以這裏不需要再次分發,直接返回,只修改mPendingData即可
if (!postTask) {
return;
}
開始在主線程執行mPostValueRunnable
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
上述代碼主要是先獲取同步鎖,檢查mPendingData是否已經設置,更新mPendingData,如果已經改變,說明消息發佈任務已啓動,無須再次啓動,然後進入postToMainThread方法看看:
@Override
public void postToMainThread(Runnable runnable) {
if (mMainHandler == null) {
synchronized (mLock) {
if (mMainHandler == null) {
獲取主線程的Looper,創建一個異步的Handler
mMainHandler = createAsync(Looper.getMainLooper());
}
}
}
handler發送runnable任務
mMainHandler.post(runnable);
}
這裏線程切換就是handler來實現的,需要了解Android handle機制看這裏
最後,再回頭看看這個Runnable是什麼任務?
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
寫入值和發送值不能同時處理,所以必須要用同一把鎖鎖住
synchronized (mDataLock) {
把值拷貝到新的newValue去,同時要設置mPendingData爲NOT_SET,
方便下次值的寫入
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
沒寫入一次值,要爲其賦一個版本號
mVersion++;
mData = value;
dispatchingValue(null);
}
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<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
這裏就是消息分發
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
private void considerNotify(ObserverWrapper observer) {
如果這個訂閱者mActive爲false,也就是小於STARTED狀態,就沒必要消息分發了
if (!observer.mActive) {
return;
}
這裏檢查的不是訂閱者,是訂閱者那邊的LifecycleOwner的狀態,這個狀態比上面的可靠
並把狀態同步給訂閱者,此時訂閱者狀態是正確的,而且也沒必要去消息分發;
這裏爲什麼要這麼做?是因爲訂閱者observer可能還不是最新的狀態,所以需要把LifecycleOwner
同步給訂閱者,以免做無用的消息分發
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
這裏搞不懂,mLastVersion都是爲啥要這麼多,會出現大於的情況嗎,我覺得不會出現,
因爲 mLastVersion都是mVersion賦值給他的,他肯定比mVersion小啊
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
執行onChanged方法,就是最初的Observer的回調函數
observer.mObserver.onChanged((T) mData);
}
以上消息分發就完成了,做個小結:
- 注意post和set的區別,主線程和任意線程
- post會出現多線程共同使用mPendingData的情況,所以要加鎖,並且使用完後要mPendingData重置爲NOT_SET
- 最後就是在消息通知時要先判斷一下訂閱者狀態,小於STARTED不需要分發,因爲訂閱者狀態可能會有延遲,就把訂閱者所屬的LifecycleOwner的狀態給他同步過來,false也不往下發
- 最後更新版本號,然後執行onChanged
銷燬訂閱者
訂閱者自身狀態DESTROYED死亡後,需要將自己從LiveData中remove掉,主要發生在LiveData的內部類LifecycleBoundObserver中的onStateChanged方法裏面,因爲LifecycleBoundObserver實現了LifecycleEventObserver接口,在訂閱者那邊LifecycleOwner提前在LiveData的observer方法最後將LifecycleBoundObserver添加進去了,也就是添加到了LifecycleOwner的訂閱者集合,所以當LifecycleOwner狀態變化時,會將狀態同步給他的訂閱者,也就是LifecycleBoundObserver,當處於DESTROY時,就會將同步調用LifecycleBoundObserver的onStateChanged方法,方法如下:
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
assertMainThread("removeObserver");
ObserverWrapper removed = mObservers.remove(observer);
if (removed == null) {
return;
}
removed.detachObserver();
removed.activeStateChanged(false);
}
上面的文字描述比較複雜,難理解,你要理解的是LifecycleBoundObserver是對LiveData的訂閱封裝類,LiveData添加了LifecycleBoundObserver,用於消息通知;而LifecycleOwner也添加了這個LifecycleBoundObserver,這邊添加是爲了生命狀態同步,需要配合Android Lifecycle疑問看看;大致簡圖如下:
總結
LiveData採用觀察者模式,一有數據更新時,會發布給訂閱者;與很好的與視圖解耦,也無須擔心內存泄漏的問題,除非LiveData本身持有其他的外部引用導致自身無法釋放;因爲在Activity這端,會實時的把自身狀態同步給LifecycleBoundObserver,以便在DESTROY狀態下,liveData會自動remove掉訂閱者