Android消息总线LiveDataBus
Android 的生命周期比较复杂,一般情况下只能覆写 Activity / Fragment 的回调方法(onCreate、onResume、onPause、onStop、onDestroy 等)才能监听生命周期,样板代码少不了,可维护性也较差。
Google 为了帮助 Android 开发者更快更好地开发 App,推出了一系列组件,这些组件被打包成了一个整体,称作 Android Jetpack,其中部分组件组成了Android Architecture Components,以下简称 AAC。
其中LiveData是其中一个组件, LiveData是一个观察者模型,观察 Lifecycle 的变化从而影响数据的分发。正是由于LiveData对组件生命周期可感知特点,因此可以做到仅在组件处于生命周期的激活状态时才更新UI数据。
LiveData需要一个观察者对象,一般是Observer类的具体实现。当观察者的生命周期处于STARTED或RESUMED状态时,LiveData会通知观察者数据变化;在观察者处于其他状态时,即使LiveData的数据变化了,也不会通知。
LiveDataBus 与其他总线对比
优点
- LiveData具有生命周期感知的能力,只有在活跃状态才会通知数据变化,非常适合作为Android通信总线的基础构件。
- 与其他总线相比,LiveData使用者不用显示调用反注册方法,避免内存泄露等其他界面结束后的异常情况。
- LiveDataBus 实现简单,依赖官方组件LiveData。如果已经使用了AAC或者 Android Jetpack全家桶LiveData几乎不会增加包大小。
缺点
LiveData
只存储最新的数据,setValue
在UI线程执行,及时更新状态到活跃页面,postValue
非UI线程更新状态,快速调用只有最新的数据会被送达。虽然LiveData用法类似 RxJava2 的 Flowable,但是它不支持背压(backpressure),所以不是一个流(stream),利用 LiveDataReactiveStreams 我们可以实现 Flowable 和 LiveData 的互换。LiveData
是一个观察者模型,但是它是一个与Lifecycle
绑定了的Subject
,也就是说,只有当 UI 组件处于 ACTIVE 状态时,它的Observer
才能收到消息,否则会自动切断订阅关系,不会像RxJava
那样可以通过CompositeDisposable
来手动处理。这是个优点,同时在某些场景也会被认为是缺点。- LiveData 的数据天生是sticky的,在LiveData后注册的observe会收到上次LiveData发送的消息,如果我们要把 LiveData 用作事件总线,还需要做一些定制。
LiveDataBus 的实现
public class LiveDataBus {
private static volatile LiveDataBus instance;
private final ConcurrentHashMap<Object, BusLiveData<Object>> mBus;
private LiveDataBus() {
mBus = new ConcurrentHashMap<>();
}
public static LiveDataBus get() {
if (instance == null) {
synchronized (LiveDataBus.class) {
if (instance == null) {
instance = new LiveDataBus();
}
}
}
return instance;
}
public <T> MutableLiveData<T> subscribe(Object eventKey, Class<T> type) {
String key = eventKey.toString();
if (mBus.containsKey(key) && mBus.get(key) != null) {
BusLiveData busLiveData = mBus.get(key);
busLiveData.firstSubscribe = false;
} else {
mBus.put(key, new BusLiveData<>(key, true));
}
return (MutableLiveData<T>) mBus.get(key);
}
public <T> MutableLiveData<T> setValue(T eventKey, T value) {
Class<T> tClass = (Class<T>) value.getClass();
MutableLiveData<T> mutableLiveData = subscribe(eventKey, tClass);
mutableLiveData.setValue(value);
return mutableLiveData;
}
public <T> MutableLiveData<T> postValue(T eventKey, T value) {
Class<T> tClass = (Class<T>) value.getClass();
MutableLiveData<T> mutableLiveData = subscribe(eventKey, tClass);
mutableLiveData.postValue(value);
return mutableLiveData;
}
public static class BusLiveData<T> extends MutableLiveData<T> {
private boolean firstSubscribe;
private String key;
BusLiveData(String key, boolean firstSubscribe) {
this.key = key;
this.firstSubscribe = firstSubscribe;
}
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
super.observe(owner, new ObserverWrapper<>(observer, firstSubscribe));
}
@Override
public void observeForever(@NonNull Observer<? super T> observer) {
super.observeForever(new ObserverWrapper<>(observer, firstSubscribe));
}
@Override
public void removeObserver(@NonNull Observer<? super T> observer) {
super.removeObserver(observer);
if (!hasObservers()) {
LiveDataBus.get().mBus.remove(key);
}
}
}
private static class ObserverWrapper<T> implements Observer<T> {
private Observer<T> observer;
private boolean isChanged;
private ObserverWrapper(Observer<T> observer, boolean isFirstSubscribe) {
this.observer = observer;
isChanged = isFirstSubscribe;
}
@Override
public void onChanged(@Nullable T t) {
if (isChanged) {
if (observer != null) {
observer.onChanged(t);
}
} else {
isChanged = true;
}
}
}
}
上面提到LiveData的缺点时说过:在LiveData后注册的observe会收到上次LiveData发送的消息,所以上面代码定制了firstSubscribe字段避免这种情况发生。
使用方法:
LiveDataBus.get().subscribe("test", Boolean.class).observe(this, new Observer<Boolean>() {
@Override
public void onChanged(@Nullable Boolean aBoolean) {
}
});
ps:如果希望在任何时候都监听消息可以使用observeForever
方法,如果只是希望在更广阔的生命周期监听,比如说在create到destroy之间监听事件,可以参考继承修改LifecycleBoundObserver
类的shouldBeActive
方法,具体实现参考ExternalLiveData