一、LiveData
LiveData是17年GoogleIO大會上提出來的一個新技術(shù)。相對于通信總線類型的框架EventBus和RxBus來說,它更簡單,更簡潔、更解耦。
它具有以下優(yōu)點:
UI和實時數(shù)據(jù)保持一致
因為LiveData采用的是觀察者模式,這樣一來就可以再數(shù)據(jù)發(fā)生改變時獲得通知,更新UI
避免內(nèi)存泄漏
觀察者被綁定到組件的生命周期上,當(dāng)被綁定的組件銷毀(Destory)時,觀察者會立刻自動清理自身的數(shù)據(jù)。
不會再產(chǎn)生由于Activity處于stop狀態(tài)而引起的崩潰
當(dāng)Activity處于后臺狀態(tài)時,是不會收到LiveData的任何事件的
不需要再解決生命周期帶來的問題
LiveData可以感知被綁定的組件的生命周期,只有在活躍狀態(tài)才會通知數(shù)據(jù)變化
實時數(shù)據(jù)刷新
當(dāng)組件處于活躍狀態(tài)或者從不活躍狀態(tài)到活躍狀態(tài)時總是能收到最新的數(shù)據(jù)
解決Confinguration Change問題
在屏幕發(fā)生旋轉(zhuǎn)或者被回收再次啟動,立刻就能收到最新的數(shù)據(jù)
二、簡要分析運用方式:
當(dāng) LiveData 所持有的數(shù)據(jù)改變時,它會通知相應(yīng)的界面代碼進(jìn)行更新。
同時,LiveData 持有界面代碼 Lifecycle (生命周期組件)的引用,這意味著它會在界面代碼(LifecycleOwner)的生命周期處于 started 或 resumed 時作出相應(yīng)更新,而在 LifecycleOwner 被銷毀時停止更新。
另外ViewModel的優(yōu)點也很明顯,為Activity 、Fragment存儲數(shù)據(jù),直到完全銷毀。尤其是屏幕旋轉(zhuǎn)的場景,常用的方法都是通過onSaveInstanceState()保存數(shù)據(jù),再在onCreate()中恢復(fù)。
既然LiveData 在線程中傳遞事件這么優(yōu)秀,那么我們應(yīng)用到項目總的話,就可以集成到一塊。這樣就誕生了LiveDataBus。
三、LiveDataBus優(yōu)點:
LiveDataBus的實現(xiàn)及其簡單
相對EventBus復(fù)雜的實現(xiàn),LiveDataBus只需要一個類就可以實現(xiàn)
LiveDataBus可以減小APK包的大小
LiveDataBus只依賴Android官方組件LiveData,本身實現(xiàn)只一個類。EventBus 57Kb、RxJava 2.2M
LiveDataBus 依賴方支持更好
LiveDataBus只依賴Android官方組件LiveData,相比RxBus依賴的RxJava和RxAndroid,依賴方支持更好
LiveDataBus具有生命周期感知
LiveDataBus具有生命周期感知,在Android系統(tǒng)中使用調(diào)用者不需要調(diào)用反注冊,相比EventBus和RxBus使用更為方便,并且沒有內(nèi)存泄漏風(fēng)險。
四、代碼展示:
以上我們已經(jīng)知道了,LiveData訂閱消息和發(fā)送消息的方式。
那么應(yīng)用到項目中時,使用Map將這些LiveData保存記錄下來,這樣各個頁面的調(diào)用存取都可以寫到同一個Map中,就形成總線機制。
訂閱消息
1、observe 生命周期感知,不需要手動取消訂閱
LiveDataBus.get().with("key_name", String.class)
.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
}
});
2、observeForever 需要手動取消訂閱
LiveDataBus.get().with("key_name", String.class).observeForever(observer);
LiveDataBus.get().with("key_name", String.class).removeObserver(observer);
發(fā)送消息
1、setValue 在主線程發(fā)送消息
LiveDataBus.get().with("key_name").setValue(value);
2、postValue 在后臺線程發(fā)送消息,訂閱者會在主線程收到消息
LiveDataBus.get().with("key_name").postValue(value);
Sticky模式
支持在注冊訂閱者的時候設(shè)置Sticky模式,這樣訂閱者可以接收到訂閱之前發(fā)送的消息
observeSticky 生命周期感知,不需要手動取消訂閱,Sticky模式
LiveDataBus.get()
.with("sticky_key", String.class)
.observeSticky(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
}
});
observeStickyForever 需要手動取消訂閱,Sticky模式
LiveDataBus.get().with("sticky_key", String.class).observeStickyForever(observer);
LiveDataBus.get().with("sticky_key", String.class).removeObserver(observer);
public final class LiveDataBus {
private final Map<String, BusMutableLiveData<Object>> bus;
private LiveDataBus() {
bus = new HashMap<>();
}
private static class SingletonHolder {
private static final LiveDataBus DEFAULT_BUS = new LiveDataBus();
}
public static LiveDataBus get() {
return SingletonHolder.DEFAULT_BUS;
}
public synchronized <T> BusMutableLiveData<T> with(String key, Class<T> type) {
if (!bus.containsKey(key)) {
bus.put(key, new BusMutableLiveData<>());
}
return (BusMutableLiveData<T>) bus.get(key);
}
public BusMutableLiveData<Object> with(String key) {
return with(key, Object.class);
}
private static class ObserverWrapper<T> implements Observer<T> {
private Observer<T> observer;
public ObserverWrapper(Observer<T> observer) {
this.observer = observer;
}
@Override
public void onChanged(@Nullable T t) {
if (observer != null) {
if (isCallOnObserve()) {
return;
}
observer.onChanged(t);
}
}
private boolean isCallOnObserve() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
if (stackTrace != null && stackTrace.length > 0) {
for (StackTraceElement element : stackTrace) {
if ("android.arch.lifecycle.LiveData".equals(element.getClassName()) &&
"observeForever".equals(element.getMethodName())) {
return true;
}
}
}
return false;
}
}
public static class BusMutableLiveData<T> extends MutableLiveData<T> {
private class PostValueTask implements Runnable {
private Object newValue;
public PostValueTask(@NonNull Object newValue) {
this.newValue = newValue;
}
@Override
public void run() {
setValue((T) newValue);
}
}
private Map<Observer, Observer> observerMap = new HashMap<>();
private Handler mainHandler = new Handler(Looper.getMainLooper());
@Override
public void postValue(T value) {
mainHandler.post(new PostValueTask(value));
}
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
super.observe(owner, observer);
try {
hook(observer);
} catch (Exception e) {
e.printStackTrace();
}
}
public void observeSticky(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
super.observe(owner, observer);
}
@Override
public void observeForever(@NonNull Observer<T> observer) {
if (!observerMap.containsKey(observer)) {
observerMap.put(observer, new ObserverWrapper(observer));
}
super.observeForever(observerMap.get(observer));
}
public void observeStickyForever(@NonNull Observer<T> observer) {
super.observeForever(observer);
}
@Override
public void removeObserver(@NonNull Observer<T> observer) {
Observer realObserver = null;
if (observerMap.containsKey(observer)) {
realObserver = observerMap.remove(observer);
} else {
realObserver = observer;
}
super.removeObserver(realObserver);
}
private void hook(@NonNull Observer<T> observer) throws Exception {
//get wrapper's version
Class<LiveData> classLiveData = LiveData.class;
Field fieldObservers = classLiveData.getDeclaredField("mObservers");
fieldObservers.setAccessible(true);
Object objectObservers = fieldObservers.get(this);
Class<?> classObservers = objectObservers.getClass();
Method methodGet = classObservers.getDeclaredMethod("get", Object.class);
methodGet.setAccessible(true);
Object objectWrapperEntry = methodGet.invoke(objectObservers, observer);
Object objectWrapper = null;
if (objectWrapperEntry instanceof Map.Entry) {
objectWrapper = ((Map.Entry) objectWrapperEntry).getValue();
}
if (objectWrapper == null) {
throw new NullPointerException("Wrapper can not be bull!");
}
Class<?> classObserverWrapper = objectWrapper.getClass().getSuperclass();
Field fieldLastVersion = classObserverWrapper.getDeclaredField("mLastVersion");
fieldLastVersion.setAccessible(true);
//get livedata's version
Field fieldVersion = classLiveData.getDeclaredField("mVersion");
fieldVersion.setAccessible(true);
Object objectVersion = fieldVersion.get(this);
//set wrapper's version
fieldLastVersion.set(objectWrapper, objectVersion);
}
}
}
注:
在BusMutableLiveData類中,hook函數(shù)利用反射機制重新給wrapper的version賦值了。跟蹤源碼可知:這么操作的意義是為了在Activity未創(chuàng)建時,不接收發(fā)布消息者發(fā)布過來的消息。(例:網(wǎng)絡(luò)請求后使用LiveData向AActivity發(fā)送消息,但是AActivity還未創(chuàng)建,這樣一旦AActivity創(chuàng)建后onResume函數(shù)調(diào)用,View會跟著數(shù)據(jù)變化。但如果我不想AActivity創(chuàng)建后View有所改變呢,就使用調(diào)用hook函數(shù)的observe去訂閱就可以了)