EventBus 源码的阅读03 - EventBus 的注册(
在上篇中, 分析学习了 EventBus 注册过程中的第一步. 就是获取注册类中所有的订阅方法.
下篇主要分析的是在获得所有订阅方法后, 逐个对他们进行订阅.
那么具体是如何进行订阅的呢. 下面直接进入正题.
EventBus.register(Object subscriber)
public void register(Object subscriber) {
//通过反射获得订阅者的 Class 对象
Class<?> subscriberClass = subscriber.getClass();
//通过订阅者 Class 对象找到该对象内所有的订阅方法集合
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
//遍历并进行单个方法的订阅
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
看代码, 在获得 subscriberMethods 集合后, 就开始了遍历整个集合, 并调用了 subscribe(Object subscriber, SubscriberMethod subscriberMethod) 方法. 传入订阅者与订阅者内部的某个订阅方法这两个参数, 准备开始订阅.
2. EventBus.subscribe(subscriber, subscriberMethod)
// Must be called in synchronized block
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<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
//分析三
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
//分析四
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
//分析 5
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 {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
因为代码过长, 所以讲 subscribe 方法分为两个部分来分析. 第一部分是正常处理流程, 第二部分是粘性事件的处理流程.
开始分析第一部分之前, 再回忆一下在第一章中创建 EventBus 对象中的两个重要的 Map 集合, 以便加深印象, 也更容易加深对本篇内容的理解.
(这里就不再贴图了, 直接以文字描述了. 想看图的可以去 EventBus 源码的阅读01 - EventBus 对象的创建 中查看.)
- private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType
以当前Event事件为key, 以CopyOnWriteArrayList<Subscription>列表为value.
Subscription可以理解为一条订阅记录, 这个记录中又包含了两个内容, 一个是包含了订阅这个Event事件的subscriber订阅者(反射执行对象),一个是SubscriberMethod. (订阅方法的包装类.)
这个 map 的目的是为了在发送 Event 事件的时候, 以 Event 事件为 key 直接在这个 map 中找到所有订阅了这个事件的 Subscription(订阅记录)列表. 找到列表后, 就可以针对列表内的每一条订阅记录进行发送事件.
- private final Map<Object, List<Class<?>>> typesBySubscriber
以subscriber订阅者为key, 以订阅者中订阅的所有Event事件类型列表为value.
订阅者到事件列表的 map, 这样订阅者向 EventBus 注册与解除注册的时候可以根据订阅者获取该订阅者订阅的所有事件, 对每个事件分别进行操作.
-
分析一
-
先获取订阅方法的事件类型, 也就是订阅方法的参数
eventType. -
接着根据方法传入的参数
subscriber订阅者及subscriberMethod订阅方法, 创建一条订阅记录newSubscription. -
以在 1 处获得的事件类型
eventType为key, 从subscriptionsByEventType中获取到所有订阅了这个事件的订阅记录列表subscriptions.
-
-
分析二
-
判断获取到的订阅记录列表
subscriptions是否为null, 也就是说判断缓存中有没有当前事件的订阅记录.
Ps: 默认第一次执行这里是为null, 但是如果是使用了索引类编译时注解处理的方式, 这里就会有值. -
如果为
null, 说明没有任何订阅记录, 那就创建一个新的订阅记录列表subscriptions, 并将这个订阅记录列表添加到subscriptionsByEventType中. -
如果不为
null, 说明当前事件有被订阅过, 但是不知道是不是当前订阅者订阅的, 有可能是别的订阅者也订阅了这个事件. 那么接着判断是否存在相同的订阅记录, 存在则直接抛出异常. 当前订阅者已经注册过这个事件. 属于重复订阅.
Ps: 注意, 这里只是处理了订阅记录列表subscriptions中包含了newSubscription的情况, 并没有处理没有包含的情况, 也没有将newSubscription添加到subscriptions中. 在分析 3 中才会添加进去.
-
-
分析三
-
获取订阅了当前事件的订阅记录列表
subscriptions的长度. -
遍历订阅记录列表
subscriptions, 根据优先级将我们在 2 中创建的单条订阅记录newSubscription, 插入到指定位置.
至此, 已经将我们需要缓存的当前事件的订阅记录
newSubscription放到了subscriptions列表中. 而subscriptions列表又存在于subscriptionsByEventType这个map的与当前事件对应的value中.
所以也可以简单的理解为, 我们往subscriptionsByEventType这map中存放了一条数据.key就是当前事件,value是一个列表, 这个列表中包含了所有订阅了这个事件的订阅记录. -
-
分析四
- 先根据
subscriber订阅者从typesBySubscriber中获取当前订阅者中所有的订阅事件类型列表subscribedEvents. 接着对这个列表进行判断. 如果没有那么就创建一个订阅事件类型列表subscribedEvents, 并将这个列表放入到typesBySubscriber这个map中.key为当前订阅者. - 接着将当前的订阅事件类型存入到
subscribedEvents列表中.
- 先根据
-
分析五
- 判断订阅方法是否为粘性事件. 如果不是粘性事件就直接执行完毕, 就为当前订阅者的订阅方法订阅完毕, 返回到
EventBus.register方法的循环中, 继续为下一个订阅方法订阅. - 如果订阅方法是粘性事件, 但是不支持继承关系. (默认为
true). 则直接就调用checkPostStickyEventToSubscription方法开始分发本次粘性事件. - 如果订阅方法是粘性事件, 同时
eventInheritance = true, 表示支持继承关系. 那么就获取所有粘性事件的Set集合. 并遍历这个集合. 依次调用checkPostStickyEventToSubscription方法分发集合中的每一个粘性事件.
- 判断订阅方法是否为粘性事件. 如果不是粘性事件就直接执行完毕, 就为当前订阅者的订阅方法订阅完毕, 返回到
到这里 EventBus 的注册流程分析完了. 总结后大致流程如下:
- 根据
EventBus.getDefault().register(this)中的这个 this, 作为订阅者. - 根据订阅者获取订阅者内部的所有订阅方法.
- 接着遍历订阅者内部的所有订阅方法, 进行订阅.
- 订阅的时候会先判断是否订阅过这个事件.
- 按照优先级将订阅记录加入到 subscriptionsByEventType 的 value 的 list 中
- 将当前事件类型加入到订阅者对应的订阅事件列表中 (typesBySubscriber 的 value 的 list 中)
- 是否是粘性事件.
- 调用 checkPostStickyEventToSubscription 分发事件.