转载
EventBus 结构
结构 | 说明 |
---|---|
Map<Class<?>, CopyOnWriteArrayList> subscriptionsByEventType 根据事件类型归类 | key:事件类型 value:订阅该事件的 订阅者、回调方法 收到一个事件时,根据事件类型, 快速找到所有订阅者、及订阅者的回调方法 |
Map<Object, List<Class<?>>> typesBySubscriber 根据订阅者归类 | key:订阅者 value:每个订阅者 所监听的 事件类型表 取消注册时可以通过该表中保存的信息 快速删除 订阅者的注册信息,避免遍历查找 |
MainThreadSupport | 用于创建 mainThreadPoster = new HandlerPoster(eventBus, looper, 10); HandlerPoster 是一个绑定了主线程的 Handler |
Poster mainThreadPoster | 控制回调函数在主线程中调用 利用 Handler 的消息队列存放事件 |
BackgroundPoster backgroundPoster | 控制回调函数在后台线程(线程池)调用 用一个 单链表 存放事件 |
AsyncPoster asyncPoster | 控制回调函数在线程池调用 用一个 单链表 存放事件 |
ExecutorService executorService | 用于执行 BACKGROUND / ASYNC 类型事件回调的线程池 core = 0 maxSize = Integer.MAX_VALUE keepAlive = 60 秒 |
Map<Class<?>, List<Class<?>>> eventTypesCache | key:EventClass value:该Class实现的接口 会循环遍历获取 EventClass 的父类,及父类实现的接口 |
Map<Class<?>, Object> stickyEvents | 粘性事件存储容器 key:EventClass 事件类型 value:粘性事件列表 粘性事件:EventBus # postSticky(event) 发送 1、粘性事件发送时会把 [EventClass, event] 的方式存入 stickyEvents 下次注册订阅者时,发现有粘性事件,直接从缓存获取事件、发送 2、postSticky(event) 发送同类型的粘性事件,会覆盖之前该类型的粘性事件 stickEvents 的 key 是事件类 Class 相同 Class 的粘性事件只会存一份,新的覆盖旧的 |
三个 Poster
Poster | 说明 |
---|---|
ThreadMode # POSTING | 在 调用 post 所在的线程执行回调,不需要 poster 来调度,直接运行 |
ThreadMode # MAIN | 在UI线程回调,如果 post 所在线程为UI 线程则直接运行,否则通过 mainThreadPoster 调度 |
ThreadMode # MAIN_ORDERED | 在UI线程回调,该模式下,事件会塞到队列中等待执行,不会阻塞主线程 |
ThreadMode # BACKGROUND | 在 Background 线程回调 如果post所在线程非UI线程,则直接执行,否则通过 backgroundPoster调度 |
ThreadMode # ASYNC | 交给线程池来管理,直接通过 asyncPoster调度 |
ASYNC 与 BACKGROUND 的区别 | BACKGROUND 的事件,在子线程发送,则直接调用回掉函数,不会用线程池回调。 ASYNC的事件,直接用线程池来执行回调函数 |
EventBus 执行过程
索引加速
注意事项
1)混淆问题
-keep public enum org.greenrobot.eventbus.ThreadMode { public static *; }
//keep住所有被 @Subscribe 标注的方法
-keepclassmembers class * {
@de.greenrobot.event.Subscribe <methods>;
}
2)不支持跨进程
3)避免出现事件环路问题
比如,
订阅者A 接收到 事件B 后,发送 事件A
订阅者B 接收到 事件A 后,发送 事件B
导致死循环。
4)复杂的事件功能,可以考虑使用 RxBus
============= 下面是源码分析,可看可不看 ==============
核心架构
基于 观察者模式 的事件发布/订阅框架。
public class EventBus {
/* key为事件类型,value为订阅者的回调方法
* EventBus在收到一个事件时,就可以根据这个事件的类型,
* 在 subscriptionsByEventType 中找到所有监听了该事件的订阅者及处理事件的回调方法。
*/
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
/* 每个订阅者所监听的事件类型表
* 取消注册时可以通过该表中保存的信息,
* 快速删除 subscriptionByEventType 中订阅者的注册信息,避免遍历查找。
*/
private final Map<Object, List<Class<?>>> typesBySubscriber;
private final Map<Class<?>, Object> stickyEvents;
//用于获取当前线程的 PostingThreadState 对象
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
/* 用于创建 mainThreadPoster = new HandlerPoster(eventBus, looper, 10);
* HandlerPoster 是一个绑定了主线程的 Handler
*/
private final MainThreadSupport mainThreadSupport;
//控制回调函数在主线程中调用
private final Poster mainThreadPoster;
//控制回调函数在后台线程(线程池)调用
private final BackgroundPoster backgroundPoster;
//控制回调函数在线程池调用
private final AsyncPoster asyncPoster;
private final SubscriberMethodFinder subscriberMethodFinder;
//用于执行 BACKGROUND/ASYNC 类型事件回调的线程池
private final ExecutorService executorService;
/*key:EventClass,value:该Class实现的接口
* 会循环遍历获取 EventClass的父类,及父类实现的接口
*/
private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();
}
1、Map<Class<?>, CopyOnWriteArrayList> subscriptionsByEventType
key为事件类型,value为订阅者的回调方法
EventBus 在收到一个事件时,就可以根据这个事件的类型,
在 subscriptionsByEventType 中找到所有监听了该事件的订阅者及处理事件的回调方法。
2、Map<Object, List<Class<?>>> typesBySubscriber
每个订阅者 (比如一个Activity可以当作一个订阅者) 所监听的事件类型表
取消注册时可以通过该表中保存的信息,
快速删除 subscriptionByEventType 中订阅者的注册信息,避免遍历查找。
3、回调方法
回调方法,在这里被封装成了 SubscriptionMethod,
里面保存了各种参数,包括优先级、是否接收黏性事件、所在线程等。
在 register() 时,会根据注解得到订阅者的所有回调方法、以及方法回调线程、优先级等信息
封装成 SubscriptionMethod 返回给 EventBus
4、三个Poster
public enum ThreadMode {
//在调用post所在的线程执行回调,不需要 poster 来调度,直接运行。
POSTING,
//在UI线程回调,如果post 所在线程为UI 线程则直接运行,否则通过 mainThreadPoster 调度
MAIN,
//在UI线程回调,该模式下,事件会塞到队列中等待执行,不会阻塞主线程
MAIN_ORDERED,
/* 在 Background 线程回调。
* 如果post所在线程非UI线程,则直接执行,否则通过backgroundPoster调度
*/
BACKGROUND,
//交给线程池来管理,直接通过asyncPoster调度
ASYNC
}
ASYNC 与 BACKGROUND的区别:
BACKGROUND的事件,如果是在子线程发送,则直接调用回掉函数,不会用线程池回调。
ASYNC的事件,如果直接用线程池来执行回调函数。
1)Poster mainThreadPoster:用于调度事件在主线程回调
由 MainThreadSupport 创建,是一个绑定了主线程的 Handler对象 HandlerPoster。
public class HandlerPoster extends Handler implements Poster {
private final EventBus eventBus;
/* PendingPostQueue 中维护了一个单链表,用于存储需要在主线程回调的事件
* 链表元素为 PendingPost
*/
private final PendingPostQueue queue;
...
public void enqueue(Subscription subscription, Object event) {
//把事件构造成一个 PendingPost 对象
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
//PendingPost 对象 塞入队列
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
/* 调用Handler.sendMessage发送事件
* 由于该 Handler 与主线程绑定,消息会回调到主线程处理
*/
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}
@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
//主线程收到消息后,从队列头部开始取出事件
PendingPost pendingPost = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
//主线程 执行回调函数
eventBus.invokeSubscriber(pendingPost);
...
}
} finally {
handlerActive = rescheduled;
}
}
}
2)BackgroundPoster backgroundPoster:
订阅者设置了BACKGROUND 模式时,如果EventBus.getDefault().post()调用线程是主线程,
EventBus会调用 BackgroundPoster.enqueue()来调度发送事件。
final class BackgroundPoster implements Runnable, Poster {
/* PendingPostQueue 中维护了一个单链表,用于存储需要在主线程回调的事件
* 链表元素为 PendingPost
*/
private final PendingPostQueue queue;
private final EventBus eventBus;
...
public void enqueue(Subscription subscription, Object event) {
//事件封装成 PendingPost 对象,塞入队列中
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!executorRunning) {
executorRunning = true;
//用线程池来执行
eventBus.getExecutorService().execute(this);
}
}
}
@Override
public void run() {
...
//线程池中执行
while (true) {
//从队列头部开始取出事件
PendingPost pendingPost = queue.poll(1000);
...
//执行回调函数
eventBus.invokeSubscriber(pendingPost);
}
...
}
}
3)AsyncPoster asyncPoster:
订阅者设置了 ASYNC 模式时,EventBus会调用 AsyncPoster.enqueue()来调度发送事件。
class AsyncPoster implements Runnable, Poster {
/* PendingPostQueue 中维护了一个单链表,用于存储需要在主线程回调的事件
* 链表元素为 PendingPost
*/
private final PendingPostQueue queue;
private final EventBus eventBus;
...
public void enqueue(Subscription subscription, Object event) {
//把事件构造成一个 PendingPost 对象,塞入队列末尾
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
queue.enqueue(pendingPost);
//调用线程池,遍历队列,执行回调函数
eventBus.getExecutorService().execute(this);
}
@Override
public void run() {//线程池线程
//从队列头部开始取出事件
PendingPost pendingPost = queue.poll();
...
//执行回调函数
eventBus.invokeSubscriber(pendingPost);
}
}
2、EventBus 创建实例
1) EventBus.getDefault()
返回一个单例的 EventBus 对象。
2)也可以通过 EventBusBuilder 创建
EventBus.builder()
.xxx
.xxx
.addIndex(SubscriberInfoIndex)//索引加速
.build();
3、register()
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
/* 1)findSubscriberMethods()根据Class 查找到 @Subscribe 注解的方法,也是订阅者的回调函数。
* 2)遍历订阅者的每个回调方法,把每个回调方法和订阅者一起封装成 Subscription
* 3)返回封装好的回调方法列表
*/
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
//4)根据优先级把 Subscription 添加到 subscriptionsByEventType 中相应的类的 List 中
subscriptionsByEventType.put(eventType, subscriptions);
}
...
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
//5)把回调方法订阅的事件,添加到 typesBySubscriber 中对应订阅者的订阅事件List中
subscribedEvents.add(eventType);
if (subscriberMethod.sticky) {//如果回调方法由注册粘性事件
if (eventInheritance) {
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
//6)从 stickyEvents 中获取相应粘性事件,并
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
// register 完成
4、post()
public void post(Object event) {
/*currentPostingThreadState 是一个 ThreadLocal 对象
* 【1】这里通过 threadLocal 获取当前线程的 PostingThreadState 对象
*/
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
//【1.1】把事件放入 当前线程的 postingState 列表中,与线程绑定。
eventQueue.add(event);
...
//【2】循环从 eventQueue 中取出事件
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
...
}
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
...
//【3】获取事件的所有父类,并遍历
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
...
if (!subscriptionFound) {
...
post(new NoSubscriberEvent(this, event));
...
}
}
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
//【4】在 subscriptionsByEventType 中,获取 每个事件的订阅者的回调方法
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
//【5】遍历该事件的所有回调方法
for (Subscription subscription : subscriptions) {
...
postToSubscription(subscription, event, postingState.isMainThread);
...
}
return true;
}
return false;
}
/* 比根据 ThreadMode ,通过不同的 poster,
* 在对应的线程中,通过反射 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 {
invokeSubscriber(subscription, event);
}
break;
case BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
...
}
}
5、unregister()
public synchronized void unregister(Object subscriber) {
//【1】从 typesBySubscriber 中取出订阅者的所有事件类型
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
//【2】遍历所有事件
for (Class<?> eventType : subscribedTypes) {
//【3】在 subscriptionsByEventType 中,相应事件的相应队列中,删掉该订阅者
unsubscribeByEventType(subscriber, eventType);
}
//【4】从 typesBySubscriber 中删除订阅者的事件列表
typesBySubscriber.remove(subscriber);
}
//unregister 完成
...
}
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
//在 subscriptionsByEventType 中,相应事件的相应队列中,删掉该订阅者
List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
6、索引加速
1)注解处理器
索引是在初始化 EventBus时,通过 EventBusBuilder.addIndex(SubscriberInfoIndex index) 方法传进来的。
public class EventBusBuilder {
public EventBusBuilder addIndex(SubscriberInfoIndex index) {
if(subscriberInfoIndexes == null) {
subscriberInfoIndexes = new ArrayList<>();
}
/* 传进来的索引信息会保存在subscriberInfoIndexes这个List中
* 后续会通过EventBusBuilder传到相应EventBus的 SubscriberMethodFinder 实例中
*/
subscriberInfoIndexes.add(index);
return this;
}
}
//索引类
public interface SubscriberInfoIndex {
//索引类唯一方法,拿到订阅者的信息
SubscriberInfo getSubscriberInfo(Class<?> subscriberClass);
}
//EventBus 的注解处理器 用于处理 @Subscribe 注解
@SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe")
@SupportedOptions(value = {"eventBusIndex", "verbose"})
public class EventBusAnnotationProcessor extends AbstractProcessor {
//被注解表示的方法信息 (key:类,value:@Subscribe注解的方法)
private final ListMap<TypeElement, ExecutableElement> methodsByClass = new ListMap<>();
// checkHasErrors 检查出来的异常方法
private final Set<TypeElement> classesToSkip = new HashSet<>();
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
Messager messager = processingEnv.getMessager();
try {
String index = processingEnv.getOptions().get(OPTION_EVENT_BUS_INDEX);
// 如果没有在gradle中配置apt的argument,编译就会在这里报错
if (index == null) {
messager.printMessage(Diagnostic.Kind.ERROR, "No option " + OPTION_EVENT_BUS_INDEX +
" passed to annotation processor");
return false;
}
/** ... */
// 根据注解拿到所有订阅者的回调方法信息
collectSubscribers(annotations, env, messager);
// 筛掉不符合规则的订阅者
checkForSubscribersToSkip(messager, indexPackage);
if (!methodsByClass.isEmpty()) {
createInfoIndexFile(index); // 生成索引类
}
/** 打印错误 */
}
/** 下面这些方法就不再贴出具体实现了,我们了解它们的功能就行 */
// 遍历annotations,找出所有被注解标识的方法,以初始化methodsByClass
private void collectSubscribers
// 过滤掉static,非public和参数大于1的方法
private boolean checkHasNoErrors
// 检查 methodsByClass中的各个类,是否存在非public的父类和方法参数
private void checkForSubscribersToSkip
/** 下面这三个方法会把 methodsByClass 中的信息写到相应的类中 */
private void writeCreateSubscriberMethods
private void createInfoIndexFile
private void writeIndexLines
}
编译时通过 注解处理器,分析 @Subscribe 注解,利用注解标识的相关类的信息去生成相关的类。
2)注解处理器生成的类:
/** This class is generated by EventBus, do not edit. */
public class MyEventBusIndex implements SubscriberInfoIndex {
private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;
static {
SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();
// 每有一个订阅者类,就调用一次 putIndex 往索引中添加相关的信息
putIndex(new SimpleSubscriberInfo(com.xxx.MainActivity.class, true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onEvent", com.xxx.MainActivity.DriverEvent.class, ThreadMode.POSTING, 0, false),
// 类中每一个被Subscribe标识的方法都在这里添加进来
}));
}
// 下面的代码就是EventBusAnnotationProcessor中写死的了
private static void putIndex(SubscriberInfo info) {
SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
}
@Override
public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
if (info != null) {
return info;
} else {
return null;
}
}
}
编译时注解处理器生成这个索引类,
该类中把所有被 @Subscribe 注解标识的方法信息(包括方法名、方法参数类型等信息)
封装到 SimpleSubscriberInfo中。
我们拿到的索引其实就是以订阅者的类为 Key、SimpleSubscriberInfo为value的哈希表。
索引类在编译时生成,避免了在在EventBus.register()时才去遍历查找生成,
从而把在注册时需要遍历订阅者所有方法的行为,提前到在编译时完成了。
3)索引的使用
SubscriberMethodFinder.findSubscriberMethods()
class SubscriberMethodFinder {
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//从缓存找
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
//忽略索引,根据注解查找回调函数,耗时高。
subscriberMethods = findUsingReflection(subscriberClass);
} else {
//去索引中查找订阅者的回调方法
subscriberMethods = findUsingInfo(subscriberClass);
}
...
}
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
...
while (findState.clazz != null) { // 子类找完了,会继续去父类中找
// 获得订阅者类的相关信息
findState.subscriberInfo = getSubscriberInfo(findState);
// 上一步能拿到相关信息的话,就开始把方法数组封装成List
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
// checkAdd是为了避免在父类中找到的方法是被子类重写的,
// 此时应该保证回调时执行子类的方法
findState.subscriberMethods.add(subscriberMethod);
}
}
} else { // 索引中找不到,降级成运行时通过注解和反射去找
findUsingReflectionInSingleClass(findState);
}
// 上下文切换成父类
findState.moveToSuperclass();
}
// 找完后,释放FindState进对象池,并返回找到的回调方法
return getMethodsAndRelease(findState);
}
private SubscriberInfo getSubscriberInfo(FindState findState) {
// subscriberInfo 已有实例,证明本次查找需要查找上次找过的类的父类
if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
// 确定是所需查找的类
if (findState.clazz == superclassInfo.getSubscriberClass()) {
return superclassInfo;
}
}
// 从我们传进来的 subscriberInfoIndexes 中获取相应的订阅者信息
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}
}