背景
对于Android系统来说,消息传递是最基本的组件,每一个App内的不同页面,不同组件都在进行消息传递。消息传递既可以用于Android四大组件之间的通信,也可用于异步线程和主线程之间的通信。对于Android开发者来说,经常使用的消息传递方式有很多种,从最早使用的Handler、BroadcastReceiver、接口回调,到近几年流行的通信总线类框架EventBus、RxBus。Android消息传递框架,总在不断的演进之中。
为什么要用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具有生命周期感知,LiveDataBus具有生命周期感知,在Android系统中使用调用者不需要调用反注册,相比EventBus和RxBus使用更为方便,并且没有内存泄漏风险。
LiveDataBus的组成
-
消息
消息可以是任何的Object,可以定义不同类型的消息,如Boolean、String。也可以定义自定义类型的消息。 -
消息通道
LiveData扮演了消息通道的角色,不同的消息通道用不同的名字区分,名字是String类型的,可以通过名字获取到一个LiveData消息通道。 -
消息总线
消息总线通过单例实现,不同的消息通道存放在一个HashMap中。 -
订阅
订阅者通过getChannel获取消息通道,然后调用observe订阅这个通道的消息。 -
发布
发布者通过getChannel获取消息通道,然后调用setValue或者postValue发布消息。
LiveDataBus原理图
640.pngLiveDataBus使用示例
public class LiveDataBus {
//存放订阅者
private Map<String, MutableLiveData<Object>> bus;
//单例
private static LiveDataBus liveDataBus = new LiveDataBus();
private LiveDataBus(){bus = new HashMap<>();
}
public static LiveDataBus getInstance(){return liveDataBus;}
/**
* 用来给用户进行订阅(存入map)因为可能会有很多用户进行订阅,所以加上同步
* @param key
* @param type
* @param <T>
* @return
*/
public synchronized <T> MutableLiveData<T> with(String key,Class<T> type){
if(!bus.containsKey(key)){
bus.put(key,new MutableLiveData<Object>());
}
return (MutableLiveData<T>) bus.get(key);
}
public MutableLiveData<Object> with(String key) {
return with(key, Object.class);
}
}
注册订阅
//消费者订阅消息
LiveDataBus.getInstance().with("key",Boolean.class)
.observe(this, new Observer<Boolean>() {
@Override
public void onChanged(Boolean bool) {
Toast.makeText(MainActivity.this, bool+"", Toast.LENGTH_SHORT).show();
}
});
发送消息
LiveDataBus.getInstance().with("key",Boolean.class).postValue(true);
问题分析
对于LiveDataBus的第一版实现,我们发现,在使用这个LiveDataBus的过程中,订阅者会收到订阅之前发布的消息。对于一个消息总线来说,这是不可接受的。无论EventBus或者RxBus,订阅方都不会收到订阅之前发出的消息。对于一个消息总线,LiveDataBus必须要解决这个问题。
查看源码步骤分析,订阅者接收到订阅之前发布的消息是因为onChanged()方法被调用了,我们可以从这个方法开始着手查看
//LiveData.class
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
...
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
从上面代码可以分析出来,如果observer.mLastVersion >= mVersion这个条件成立,那么bserver.mObserver.onChanged((T) mData)就不会调用。我们再来分析observer.mLastVersion和mVersion两个变量我们发现mVersion这个变量是LiveData类的成员变量,初始化值为-1,每当调用一次setvalue()或者postValue()这个值就会自增
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
ObserverWrapper是观察者的包装类,里面的成员变量mLastVersion初始值也是-1,即每一个新注册的观察者的mLastVersion都是-1
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;(-1)
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}
abstract boolean shouldBeActive();
boolean isAttachedTo(LifecycleOwner owner) {
return false;
}
void detachObserver() {
}
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
if (mActive) {
dispatchingValue(this);
}
}
}
从上面分析可以得出结论,出现问题原因就是每个新注册的观察者的version小于了Livedata总线的version,即observer.mLastVersion < mVersion,所以会调用 observer.mObserver.onChanged((T) mData)方法,导致新注册的观察者会收到订阅之前的消息。
解决问题
根据上面的分析,我们只需要在注册一个新的订阅者的时候把ObserverWrapper的version设置成跟livedata的version一致就好,那么该如何实现呢。
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
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);
}
看看LiveData的observe方法,他会先创建一个LifecycleBoundObserver,LifecycleBoundObserver是ObserverWrapper的子类,然后会把这个LifecycleBoundObserver放入一个私有的map集合mObservers中。无论ObserverWrapper还是LifecycleBoundObserver都是私有的,所以无法通过继承的方式更改LifecycleBoundObserver的version。那么能不能从Map容器mObservers中取到LifecycleBoundObserver,然后再更改version呢?答案是肯定的,通过查看SafeIterableMap的源码我们发现有一个protected的get方法。因此,在调用observe的时候,我们可以通过反射拿到LifecycleBoundObserver,再把LifecycleBoundObserver的version设置成和LiveData一致即可。
代码最终实现
public class LiveDataBus {
//存放订阅者
private Map<String, BusMutableLiveData<Object>> bus;
//单例
private static LiveDataBus liveDataBus = new LiveDataBus();
private LiveDataBus() {
bus = new HashMap<>();
}
public static LiveDataBus getInstance() {
return liveDataBus;
}
/**
* 用来给用户进行订阅(存入map)因为可能会有很多用户进行订阅,所以加上同步
*
* @param key
* @param type
* @param <T>
* @return
*/
public synchronized <T> BusMutableLiveData<T> with(String key, Class<T> type) {
if (!bus.containsKey(key)) {
bus.put(key, new BusMutableLiveData<Object>());
}
return (BusMutableLiveData<T>) bus.get(key);
}
public BusMutableLiveData<Object> with(String key) {
return with(key, Object.class);
}
public static class BusMutableLiveData<T> extends MutableLiveData<T> {
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
super.observe(owner, observer);
hook(observer);
}
private void hook(Observer<? super T> observer) {
//通过反射修改mLastVersion的值
Class<LiveData> liveDataClass = LiveData.class;
try {
Field field = liveDataClass.getDeclaredField("mObservers");
field.setAccessible(true);
//获取这个字段对应的对象
Object mObject = field.get(this);
//得到SafeIterableMap.class
Class<?> aClass = mObject.getClass();
//获取到SafeIterableMap的get方法
Method get = aClass.getDeclaredMethod("get", Object.class);
get.setAccessible(true);
//执行get方法
Object invoke = get.invoke(mObject, observer);
//取到SafeIterableMap中的value
Object observerWraper = null;
if (invoke != null && invoke instanceof Map.Entry) {
observerWraper = ((Map.Entry) invoke).getValue();
}
if (observerWraper == null) {
throw new NullPointerException("observerWraper is null");
}
//得到ObserverWrapper的类对象(这里需要getSuperclass是因为map集合塞的就是ObserverWrapper的子类对象)
Class<?> superclass = observerWraper.getClass().getSuperclass();
Field mLastVersion = superclass.getDeclaredField("mLastVersion");
mLastVersion.setAccessible(true);
//得到mVersion
Field mVersion = liveDataClass.getDeclaredField("mVersion");
mVersion.setAccessible(true);
//把mVersion的值填入到mLastVersion中去
Object mVersionValue = mVersion.get(this);
mLastVersion.set(observerWraper, mVersionValue);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
源码地址:https://github.com/games2sven/JetPack_LiveDataBus
参考了美团技术团队的博客,博客地址:https://www.cnblogs.com/meituantech/p/9376449.html
网友评论