关于EventBus
- EventBus是一个轻量级的发布和订阅事件的库
- 有基本超过2W的开发者在使用
- 服务于许多大体量的App
- 集成和使用方式都特别方便
```
//订阅与解除订阅
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
//定义事件
public class MessageEvent
// 订阅者接受到事件后的回调
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event)
//发布事件
EventBus.getDefault().post(new MessageEvent());
```
疑问
EventBus是如何进行事件关联的
EventBus的核心类
- EventBus 事件发布和订阅的唯一入口
- Subscribe (注解类)用于声明事件
public @interface Subscribe {
ThreadMode threadMode() default ThreadMode.POSTING; //事件回调处理线程
boolean sticky() default false; // 是否需要粘性事件 默认false
int priority() default 0; // 优先权
}
- SubscriberMethodFinder 通过反射获取实体类中带有Subscribe注解的订阅者的相关信息,并存入集合
- SubscriberMethod 用于封装订阅者的相关信息
- Poster 接口,实现该接口的有AsyncPoster,BackgroundPoster,HandlerPoster用于处理发布的事件
事件处理流程
- 事件订阅与存储
//外部调用方法进行订阅
EventBus.getDefault().register(this);
//EventBus内用于存储订阅者的集合
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
key: 事件的Class对象
value: Subscription的集合
//Subscription内部属性
final class Subscription {
final Object subscriber; //订阅者,上述register(this)中的this
final SubscriberMethod subscriberMethod;
}
//SubscriberMethod内部属性
public class SubscriberMethod {
final Method method; //等待被事件触发的方法
final Class<?> eventType; //事件的class对象
final ThreadMode threadMode;
final int priority;
final boolean sticky;
}
在EventBus类中的register方法内。
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
这句代码主要作用就是通过放射获取订阅者及其父类中 带有Subscribe注解的方法,以及Subscribe的相关参数
由于代码太多就不贴出来了,感兴趣的同学可以去了解一下
获取相关信息后执行EventBus类中的subscribe方法,封装Subscription并存入到subscriptionsByEventType集合中
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod)
- 发布事件
//发布事件
EventBus.getDefault().post(new MessageEvent())
//通过事件的class类型 获取该事件的订阅者 执行postToSubscription方法
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}
//判断不同的threadMode调用不同的处理类进行方法放射执行 method.invoke("方法所在类的实例化对象","参数")
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case MAIN_ORDERED:
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(subscription, event);
}
break;
case BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
- 其他
EventBus.getDefault().unregister(this)
解除订阅 其实无非就是从subscriptionsByEventType集合中删除掉对应的订阅对象
EventBus.getDefault().postSticky(new MessageEvent())
发送粘性事件,流程跟发布正常的时间大致一致,postSticky方法内调用了post方法(),不过在这之前EventBus也同时将该事件加入了
private final Map<Class<?>, Object> stickyEvents;
stickyEvents用于存储的粘性事件会在有订阅者订阅时,去检测是否需要粘性事件,如果为True则会匹配stickyEvents中的粘性事件
如果有事件匹配,则会直接执行该事件
其实EventBus的主要设计模式 就是一个观察者模式,根据该模式其实我们也能手写一个属于我们自己的事件分发库
参考EventBus写的一个事件分发库,在EventBus的基础上,添加事件延迟处理功能
https://github.com/liujun123456/EngineEvent