Android总线之LiveDataBus
LiveDataBus概述
一、定义
LiveDataBus是用LiveData实现的事件总线工具类,用于实现数据传递,实现Android组件之间、组件与后台线程之间通信,可用来替换EventBus。
1.为什么要用LiveData实现事件总线呢
-
LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。
-
LiveData 具有生命周期感知能力,确保界面符合数据状态,不会发生内存泄露,不会因 Activity停止而导致崩溃,不再需要手动处理生命周期以及手动调用反注册方法,数据始终保持最新状态。
2.LiveDataBus对比EventBus、RxBus优点
-
LiveDataBus的实现简单,相对EventBus复杂的实现,LiveDataBus只需要一个类就可以实现。
-
LiveDataBus可以减小APK包的大小,由于LiveDataBus只依赖Android官方Android Architecture Components组件的LiveData,没有其他依赖,本身实现只有一个类。作为比较,EventBus JAR包大小为57kb,RxBus依赖RxJava和RxAndroid,其中RxJava2包大小2.2MB,RxJava1包大小1.1MB,RxAndroid包大小9kb。使用LiveDataBus可以大大减小APK包的大小。
-
LiveDataBus依赖方支持更好,LiveDataBus只依赖Android官方Android Architecture Components组件的LiveData,相比RxBus依赖的RxJava和RxAndroid,依赖方支持更好。
-
LiveDataBus具有生命周期感知,在Android系统中使用调用者不需要调用反注册,相比EventBus和RxBus使用更为方便,并且没有内存泄漏风险。
3.LiveDataBus缺点
- 为了解决下文介绍的出现的粘性问题,有各种反射或者侵入性比较强的解决方式
- 因为LiveData本身是单进程数据,因此不支持跨进程(也可以通过Android的跨进程方式做一个桥接比如通过AIDL实现LiveData的跨进程通信),只支持多线程
二、LiveDataBus实现
主要实现步骤
-
通过 map 维护一个消息事件和 MutableLiveData 的映射关系,MutableLiveData 的类型默认为 Object,接收任意类型,实现总线通信
-
将 LiveDataBus 封装为一个单例类
-
消息注册时,如果当前 map 中不存在,则先将消息和对应的 MutableLiveData 对象放入维护的 map 中,添加映射关系,返回当前 map 中缓存的 MutableLiveData 对象
LiveDataBus简单实现
public final class LiveDataBus {
private final Map<String, MutableLiveData<Object>> bus;
private LiveDataBus() {
bus = new HashMap<>();
}
private static class SingletonHolder {
private static final LiveDataBus DATA_BUS = new LiveDataBus();
}
public static LiveDataBus get() {
return SingletonHolder.DATA_BUS;
}
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);
}
public MutableLiveData<Object> with(String target) {
return with(target, Object.class);
}
}
使用问题
在使用这个LiveDataBus的过程中,订阅者会收到订阅之前发布的消息。对于一个消息总线来说,这是不可接受的。无论EventBus或者RxBus,订阅方都不会收到订阅之前发出的消息。对于一个消息总线,LiveDataBus必须要解决这个问题。
核心原因
对于 LiveData,其初始的 version 是-1,当我们调用了其 setValue或者 postValue,其 vesion 会+1;对于每一个观察者的封装 ObserverWrapper,其初始 version 也为-1,也就是说,每一个新注册的观察者,其 version 为-1;当LiveData 设置这个 ObserverWrapper 的时候,如果 LiveData 的 version 大于 ObserverWrapper 的 version,LiveData 就会强制把当前 value 推送给 Observer。
如何解决这个问题呢
只需要在注册一个新的订阅者的时候把 ObserverWrapper 的 version 设置成跟 LiveData 的 version 一致即可。
LiveDataBus最终实现
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> Observable<T> with(String key, Class<T> type) {
if (!bus.containsKey(key)) {
bus.put(key, new BusMutableLiveData<>(key));
}
return (Observable<T>) bus.get(key);
}
public Observable<Object> with(String key) {
return with(key, Object.class);
}
public interface Observable<T> {
// void setValue(T value);
void post(T value);
void postDelay(T value, long delay);
void postDelay(T value, long delay, TimeUnit unit);
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer);
void observeSticky(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer);
void observeForever(@NonNull Observer<? super T> observer);
void observeStickyForever(@NonNull Observer<T> observer);
void removeObserver(@NonNull Observer<? super T> observer);
}
private static class BusMutableLiveData<T> extends MutableLiveData<T> implements Observable<T> {
private class PostValueTask implements Runnable {
private Object newValue;
public PostValueTask(@NonNull Object newValue) {
this.newValue = newValue;
}
@Override
public void run() {
setValue((T) newValue);
}
}
@NonNull
private final String key;
private Map<Observer, Observer> observerMap = new HashMap<>();
private Handler mainHandler = new Handler(Looper.getMainLooper());
private BusMutableLiveData(String key) {
this.key = key;
}
public boolean isMainThread() {
return Looper.getMainLooper().getThread() == Thread.currentThread();
}
@Override
public void post(T value) {
if(isMainThread()) setValue(value);
else mainHandler.post(new PostValueTask(value));
}
@Override
public void postDelay(T value, long delay) {
mainHandler.postDelayed(new PostValueTask(value), delay);
}
@Override
public void postDelay(T value, long delay, TimeUnit unit) {
postDelay(value, TimeUnit.MILLISECONDS.convert(delay, unit));
}
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
SafeCastObserver<T> safeCastObserver = new SafeCastObserver(observer);
//保存LifecycleOwner的当前状态
Lifecycle lifecycle = owner.getLifecycle();
Lifecycle.State currentState = lifecycle.getCurrentState();
int observerSize = getLifecycleObserverMapSize(lifecycle);
boolean needChangeState = currentState.isAtLeast(Lifecycle.State.STARTED);
if (needChangeState) {
//把LifecycleOwner的状态改为INITIALIZED
setLifecycleState(lifecycle, Lifecycle.State.INITIALIZED);
//set observerSize to -1,否则super.observe(owner, observer)的时候会无限循环
setLifecycleObserverMapSize(lifecycle, -1);
}
super.observe(owner, safeCastObserver);
if (needChangeState) {
//重置LifecycleOwner的状态
setLifecycleState(lifecycle, currentState);
//重置observer size,因为又添加了一个observer,所以数量+1
setLifecycleObserverMapSize(lifecycle, observerSize + 1);
//把Observer置为active
hookObserverActive(safeCastObserver, true);
}
//更改Observer的version
hookObserverVersion(safeCastObserver);
}
public void observeSticky(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
super.observe(owner, new SafeCastObserver<>(observer));
}
@Override
public void observeForever(@NonNull Observer<? super 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<? super T> observer) {
Observer realObserver = null;
if (observerMap.containsKey(observer)) {
realObserver = observerMap.remove(observer);
} else {
realObserver = observer;
}
super.removeObserver(realObserver);
if (!hasObservers()) {
LiveDataBus.get().bus.remove(key);
}
}
private void setLifecycleObserverMapSize(Lifecycle lifecycle, int size) {
if (lifecycle == null) {
return;
}
if (!(lifecycle instanceof LifecycleRegistry)) {
return;
}
try {
Field observerMapField = LifecycleRegistry.class.getDeclaredField("mObserverMap");
observerMapField.setAccessible(true);
Object mObserverMap = observerMapField.get(lifecycle);
Class<?> superclass = mObserverMap.getClass().getSuperclass();
Field mSizeField = superclass.getDeclaredField("mSize");
mSizeField.setAccessible(true);
mSizeField.set(mObserverMap, size);
} catch (Exception e) {
e.printStackTrace();
}
}
private int getLifecycleObserverMapSize(Lifecycle lifecycle) {
if (lifecycle == null) {
return 0;
}
if (!(lifecycle instanceof LifecycleRegistry)) {
return 0;
}
try {
Field observerMapField = LifecycleRegistry.class.getDeclaredField("mObserverMap");
observerMapField.setAccessible(true);
Object mObserverMap = observerMapField.get(lifecycle);
Class<?> superclass = mObserverMap.getClass().getSuperclass();
Field mSizeField = superclass.getDeclaredField("mSize");
mSizeField.setAccessible(true);
return (int) mSizeField.get(mObserverMap);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
private void setLifecycleState(Lifecycle lifecycle, Lifecycle.State state) {
if (lifecycle == null) {
return;
}
if (!(lifecycle instanceof LifecycleRegistry)) {
return;
}
try {
Field mState = LifecycleRegistry.class.getDeclaredField("mState");
mState.setAccessible(true);
mState.set(lifecycle, state);
} catch (Exception e) {
e.printStackTrace();
}
}
private Object getObserverWrapper(@NonNull Observer<T> observer) throws Exception {
Field fieldObservers = LiveData.class.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();
}
return objectWrapper;
}
private void hookObserverVersion(@NonNull Observer<T> observer) {
try {
//get wrapper's version
Object objectWrapper = getObserverWrapper(observer);
if (objectWrapper == null) {
return;
}
Class<?> classObserverWrapper = objectWrapper.getClass().getSuperclass();
Field fieldLastVersion = classObserverWrapper.getDeclaredField("mLastVersion");
fieldLastVersion.setAccessible(true);
//get livedata's version
Field fieldVersion = LiveData.class.getDeclaredField("mVersion");
fieldVersion.setAccessible(true);
Object objectVersion = fieldVersion.get(this);
//set wrapper's version
fieldLastVersion.set(objectWrapper, objectVersion);
} catch (Exception e) {
e.printStackTrace();
}
}
private void hookObserverActive(@NonNull Observer<T> observer, boolean active) {
try {
//get wrapper's version
Object objectWrapper = getObserverWrapper(observer);
if (objectWrapper == null) {
return;
}
Class<?> classObserverWrapper = objectWrapper.getClass().getSuperclass();
Field mActive = classObserverWrapper.getDeclaredField("mActive");
mActive.setAccessible(true);
mActive.set(objectWrapper, active);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static class ObserverWrapper<T> implements Observer<T> {
@NonNull
private final Observer<T> observer;
ObserverWrapper(@NonNull Observer<T> observer) {
this.observer = observer;
}
@Override
public void onChanged(@Nullable T t) {
if (isCallOnObserve()) {
return;
}
try {
observer.onChanged(t);
} catch (ClassCastException e) {
e.printStackTrace();
}
}
private boolean isCallOnObserve() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
if (stackTrace != null && stackTrace.length > 0) {
for (StackTraceElement element : stackTrace) {
if ("androidx.lifecycle.LiveData".equals(element.getClassName()) &&
"observeForever".equals(element.getMethodName())) {
return true;
}
}
}
return false;
}
}
private static class SafeCastObserver<T> implements Observer<T> {
@NonNull
private final Observer<T> observer;
SafeCastObserver(@NonNull Observer<T> observer) {
this.observer = observer;
}
@Override
public void onChanged(@Nullable T t) {
try {
observer.onChanged(t);
} catch (ClassCastException e) {
e.printStackTrace();
}
}
}
public static <T> Observable<T> get(@NonNull String key, @NonNull Class<T> type) {
return get().with(key, type);
}
public static <T> Observable<T> get(@NonNull String key) {
return (Observable<T>)get(key, Object.class);
}
public static <T > Observable<T> get(@NonNull Class<T> eventType) {
return get(eventType.getName(), eventType);
}
}
三、使用
上述代码实现了一个通信总线的全部功能,并且还具有生命周期感知功能,使用起来也及其简单,具体使用如下:
- 注册订阅:
LiveDataBus.get("test", Boolean.class)
.observe(this, new Observer<Boolean>() {
@Override
public void onChanged(Boolean aBoolean) {
}
});
注意:observe仅更新处于活动生命周期状态的应用程序组件观察者,如果需要不受生命周期的影响,只要数据更新就会收到通知可以使用observeForever,这意味着给定的观察者将接收所有事件,并且永远不会被自动删除。需要手动调用removeObserver(Observer)来停止这个LiveData。
- 发送消息:
LiveDataBus.get("test").post(true);
注意:livedata的setValue只可在主线程下使用,多线程下可使用postValue,当然主线程也可以使用这个。这里实现了自己的post方法,统一判断当前所在线程,调用合适的方式。