??????網上關于DataBinding,ViewModel,LiveData文章很多,最近結合源碼及相關實例分析了一下,本文結合LiveData的使用來對LiveData進行源碼分析。
??????關于DataBinding的使用,可以參考之前的文章:
??????Android JetPack DataBinding分析
一.LiveData簡介
??????LiveData 是一個可觀察的數據持有者類。與常規 observable 不同,LiveData 是生命周期感知的,這意味著它尊重其他應用程序組件的生命周期,例如 activity,fragment。此感知確保 LiveData僅更新處于活動狀態的應用組件觀察者。
??????如果 Observer 類表示的觀察者生命周期處于 STARTED
或 RESUMED
狀態,則 LiveData 會將其視為活動狀態。LiveData 僅通知處于活動狀態的觀察者更新信息。非活動狀態的觀察者不會收到有關數據更改的通知。
??????你可以注冊與實現了 LifecycleOwner
接口的對象配對的觀察者。此關系允許在相應 Lifecycle
對象的狀態更改為 DESTROYED
時刪除觀察者。這對于 activity 和 fragment 特別有用,因為它們可以安全地觀察 LiveData 對象而不用擔心泄漏 - activity 和 fragment 在其生命周期被銷毀時立即取消訂閱。
二.LiveData使用
??????LiveData是一個抽象類,不能直接實例話,google為我們定義好了實現類MutableLiveData,可以通過MutableLiveData來創建不同類型的對象,結合代碼來看一下:
a.基礎功能
private MutableLiveData<String> mLiveData = new MutableLiveData<>();
mLiveData.observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
Toast.makeText(HookActivity.this, "receive message is " + s,Toast.LENGTH_SHORT).show();
}
});
mLiveData.setValue("test lifecycle observe");
??????通過以上可以看到,使用起來還是比較簡單的,先創建一個MutableLiveData對象,執行observe()方法,傳入當前UI實現類(A/F)的對象引用和observer(監聽data變化),執行setValue()來更新MutableLiveData的值。
b.進階功能
??????UI內實現了對某個LiveData的監聽,當UI處于后臺后,此時LiveData的值進行了更新,那應該如何處理呢?結合代碼來看一下:
private void testDataObserverLifecycle() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
mLiveData.postValue("test lifecycle observe");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
??????以上方法可以看到,是啟動一個線程,然后在3s后對LiveData進行了值更新,注意一下,postValue()是在非UI線程執行的值更新調用方法,當我們在執行以上方法后,將當前界面切換到后臺,3s之后再切換回來,發現會彈出toast提示。
??????結論:LiveData會監聽UI的生命周期變化,當處于前臺后,會將值變化通知到UI。
c.全局功能
??????通過以上可以看到,當LiveData發生變化后,UI處于后臺時,是不會收到值更新的,但是當返回前臺后,會立刻收到值變化通知UI,那如果LiveData作為一個全局的變量,新的UI(A/F)啟動后監聽該LiveData會怎樣呢?結合代碼來看一下:
①.定義全局變量
??????定義一個單例模式的類,里面定義一個HashMap來存儲MutableLiveData,通過key來獲取,如果map中存在,就返回;否則創建,然后存入map。
public final class LiveDataBus {
private final Map<String, MutableLiveData<Object>> bus;
private static class InstanceHolder {
public static LiveDataBus sInstance = new LiveDataBus();
}
private LiveDataBus() {
bus = new HashMap<>();
}
public static synchronized LiveDataBus getInstance() {
return InstanceHolder.sInstance;
}
public <T> MutableLiveData<T> with(String target, Class<T> type) {
if (!bus.containsKey(target)) {
bus.put(target, new MutableLiveData<>());
}
return (MutableLiveData<T>) bus.get(target);
}
}
②.創建LiveData
??????先在Activity1內使用對應key的變量,并更新值:
private void testData() {
new Thread(new Runnable() {
@Override
public void run() {
try {
LiveDataBus.getInstance().with("key_test", String.class).postValue("LiveDataBus test");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
③.使用LiveData
??????后在類Activity2內使用對應key的變量:
LiveDataBus.getInstance().with("key_test", String.class).observe(this,
new Observer<String>() {
@Override
public void onChanged(String s) {
Toast.makeText(Activity2.this, "receive message is " + s,Toast.LENGTH_SHORT).show();
}
});
??????我們發現,會彈出Toast提示,也就是說后面創建新的UI內部使用該LiveData,也會收到回調,跟stick broadcast類似,后面注冊該broadcast時,會立刻收到廣播。
??????在對LiveData進行使用后,有了一定的了解,帶著問題去看一下LiveData的源碼。
三.LiveData源碼分析
a.observe()
??????LiveData注冊了LifecycleOwner(Activity/Fragment)生命周期的觀察者,當Activity/Fragment生命周期發生變化后,LiveData會對生命周期狀態進行判斷,來確定是否需要通知LifecycleOwner進行邏輯更新,詳情可參考Android Jetpack Lifecycle詳解,注冊邏輯如下:
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
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()時,首先確保是主線程,如果LifeCycleOwner的生命周期是destroyed時,直接返回;然后將owner及observer封裝成LifecycleBoundObserver,添加到mObservers里面,后續值發生變化時,會遍歷回調;最后將wrapper添加到owner的lifecycle生命周期的觀察者。
??????接下來看一下LifecycleBoundObserver的實現:
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
.......
@Override
//判斷owner是否處于active狀態
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
//LifecycleEventObserver實現了LifecycleObserver,owner生命周期狀態發生變化后的回調
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
//當owner生命周期狀態發生變化后,看是否需要將數據更新到owner,如果從后臺切換到前臺后,會將最新數據更新到UI[每次執行setValue()后,都會保存最新的mData = value]。
activeStateChanged(shouldBeActive());
}
......
}
??????LifecycleBoundObserver實現了LifecycleEventObserver,owner有生命周期變化后,會回調onStateChanged()方法,當其生命周期變為DESTROYED后,會移除observer,這也就是為什么我們不需要手動 remove observer 的原因,此后LiveData發生變化后,不會更新到Activity/Fragment,即不會一直持有其引用,從而不會造成內存泄露;
??????當Activity/Fragment處于前臺后,會將最新的數據更新到UI,邏輯如下:
void activeStateChanged(boolean newActive) {
......
if (mActive) {
dispatchingValue(this);
}
}
??????感知數據變化如下:
b.setValue()/postValue()
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
protected void postValue(T value) {
......
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
??????執行setValue()及postValue()后,會先更新mData為最新的value,然后執行dispatchingValue()。
c.dispatchingValue()
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;
}
??????通過以上可以看到,在執行dispatchingValue()后,會對參數進行判斷,如果不為空,會單獨調用considerNotify();如果為空,則會遍歷調用considerNotify()。
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);
}
??????通過以上可以看到,在considerNotify()內部會最終調用observer.mObserver的onChanged()方法。
d.通知途徑
??????以上可以看到,有兩種途徑會最終調用dispatchingValue():
??????1.setValue():調用dispatchingValue(null),會通知所有的observer,進而再調用considerNotify()進行更新。
??????2.A/F(LifeCycleOwner)的activeStateChanged():調用dispatchingValue(this),由于此處參數不為null,所以會單獨回調監聽該owner對應的observer。LiveData內部關聯了LifecycleOwner(Activity/Fragment)生命周期相關的方法,當LifecycleOwner生命周期變化的時候都會回調onStateChanged()方法,然后會去調用activeStateChanged(),最后調用considerNotify()方法去執行數據變化回調。
??????接收事件流程:
??????以上就是對LiveData源碼的分析,包括observe()及其內部封裝、setValue()后執行dispatchValue()、considerNotify()最終執行observer的onChanged()進行通知及數據更新。
四.LiveData粘性去除
??????以上實例可以看到,LiveData可以作為全局變量來使用,具有粘性的功能,如果不需要粘性功能,需要怎么處理呢?先看一下considerNotify()方法的內部實現:
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);
}
??????如果修改內部執行邏輯的話,可以通過hook來實現,內部有3處可以執行return,但是唯一可以hook的就是來使mLastVersion==mVersion,來使條件滿足執行return,看一下實現方式:
public final class LiveDataBus {
......
public <T> MutableLiveData<T> with(String target, Class<T> type) {
if (!bus.containsKey(target)) {
bus.put(target, new BusMutableLiveData<>());
}
return (MutableLiveData<T>) bus.get(target);
}
private static class BusMutableLiveData<T> extends MutableLiveData<T> {
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
super.observe(owner, observer);
try {
//通過設置mLastVersion = mVersion在執行considerNotify()時返回,消除粘性
hook(observer);
} catch (Exception e) {
e.printStackTrace();
}
}
private void hook(@NonNull Observer<?> observer) {
Class<?> liveDataClass = LiveData.class;
try {
Field mObserversField = liveDataClass.getDeclaredField("mObservers");
mObserversField.setAccessible(true);
Object mObservers = mObserversField.get(this);
Class<?> mObserversClass = mObservers.getClass();
Method getMethod = mObserversClass.getDeclaredMethod("get", Object.class);
getMethod.setAccessible(true);
Object entry = getMethod.invoke(mObservers, observer);
Object observerWrapper = ((Map.Entry) entry).getValue();
Class<?> observerClass = observerWrapper.getClass().getSuperclass();
Field mLastVersionField = observerClass.getDeclaredField("mLastVersion");
mLastVersionField.setAccessible(true);
Field mVersionField = liveDataClass.getDeclaredField("mVersion");
mVersionField.setAccessible(true);
Object mVersionValue = mVersionField.get(this);
mLastVersionField.set(observerWrapper, mVersionValue);
} catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
??????以上可以看到,自定義類繼承MutableLiveData類,在observe()后,執行hook(),將observer的mLastVersion的值設成跟mVersion一致就可以了。
五.LiveData 的優點:
??????a.確保你的 UI 符合你的數據狀態
??????LiveData遵循觀察者模式,狀態更改時LiveData會通知 Observer對象,觀察者可以在每次數據變化時更新UI。
??????b.沒有內存泄漏
??????觀察者綁定到 Lifecycle 對象,并在其相關生命周期被銷毀后自行清理。
??????c.不會因為 activity 停止而發生崩潰
??????如果觀察者的生命周期處于非活動狀態(例如,activity 在后臺堆棧中),則它不會接收任何 LiveData 事件。
??????d.不再需要手動處理生命周期
??????UI 組件只是觀察相關數據,不會停止或恢復觀察。LiveData自動管理所有這些,因為它在觀察時意識到相關的生命周期狀態變化。
??????e.始終保持最新數據
??????如果生命周期變為非活動狀態,它將在再次變為活動狀態時接收最新數據。例如,后臺 activity 在返回前臺后立即接收最新數據。
??????f.適當的配置更改
??????如果由于配置更改(例如設備旋轉)而重新創建 activity 或 fragment,則會立即接收最新的可用數據。
??????g.共享資源
??????可以使用單例模式擴展 LiveData 對象以包裝系統服務,以便可以在應用程序中共享它們。LiveData 對象連接到系統服務一次,然后任何需要該資源的觀察者只需觀察 LiveData 對象。
??????以上是對LiveData的使用及源碼分析,詳細理解需要重點關注LiveData這個類。