【EventBus】EventBus 源码解析 ( 注册订阅者 | 注册订阅方法详细过程 )
前言
在上一篇博客 【EventBus】EventBus 源码解析 ( 注册订阅者 | 订阅方法 | 查找订阅方法 ) 中 , 介绍了注册订阅者的第一个步骤 , 查找订阅者 ;
首先要获取当前的 List<SubscriberMethod> subscriberMethods
订阅方法集合 , 该集合从 SubscriberMethodFinder
的缓存 Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE
获取 , 该缓存是在第一次获取订阅方法时生成 , 之后获取都直接从缓存中获取即可 ;
METHOD_CACHE
缓存生成策略 : 如果是第一次获取订阅方法 , 缓存是空的 , 此时通过反射获取该 订阅类 所有符合条件的订阅方法 , 将 订阅方法 封装到 SubscriberMethod
中 , 然后添加到 findState.subscriberMethods
集合中 ;
一、EventBus 注册订阅者
获取到订阅方法集合后 , 然后开始遍历订阅方法集合 , 调用 subscribe
方法 , 注册订阅者 ;
public class EventBus {
/**
* 注册给定订阅服务器以接收事件。订阅者一旦对接收事件不再感兴趣,就必须调用{@link#unregister(Object)}。
* <p/>
* 订阅服务器具有必须由{@link Subscribe}注释的事件处理方法。
* {@link Subscribe}注释还允许类似{@link ThreadMode}和优先级的配置。
*/
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
// 1. 获取 订阅者 集合 , 查找当前订阅类中符合条件的订阅方法集合
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
// 2. 遍历 订阅者 集合 , 进行事件订阅 , 保存数据 , 这些数据就是一些映射关系
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
二、注册订阅方法的具体过程
获取订阅方法参数类型 , 可以是任意类型 , 自定义的 MessageEvent 消息类型 ;
subscribe(Object subscriber, SubscriberMethod subscriberMethod)
- 1
封装 Subscription 对象 , Subscription 中封装了一个订阅者对象和一个订阅方法 ;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
- 1
从 Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType
成员变量中获取 Subscription
集合 , 该 HashMap 的用途是保存当前的 eventType 对应的所有的订阅类和订阅方法 , 以便消息中心获取对应类型的消息后 , 可以顺利将其传递给相应订阅方法 ;
- Key 是事件类型对象 ;
- Value 是 Subscription 集合 , Subscription 中封装了一个订阅者对象和一个订阅方法
CopyOnWriteArrayList 是线程安全集合 , 写入数据的时候会拷贝一份出来 , 不会影响其它线程读取该集合的操作
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
- 1
如果上述集合中没有保存本次遍历的数据 , 则将订阅方法信息保存到上述集合中 ;
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);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如果订阅方法设置了优先级注解属性 , 则处理订阅方法优先级 , 重新进行排列 ;
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;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
向 Map<Object, List<Class<?>>> typesBySubscriber
成员变量 添加 订阅者对象 - 订阅方法参数类型集合 键值对 , 该成员变量的作用是取消注册时查找相关的订阅方法 ;
// Map<Object, List<Class<?>>> typesBySubscriber
// Key : 订阅者对象
// Value : 订阅方法参数类型集合
// 取消注册时 , 需要使用该方法
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
注册订阅方法代码示例 :
/**
* EventBus是Java和Android的中央发布/订阅事件系统。
* 事件被发布({@link#post(Object)})到总线,总线将其传递给具有匹配处理程序的订阅者
* 事件类型的方法。
* 要接收事件,订阅者必须使用{@link#register(Object)}将自己注册到总线。
* 一旦注册,订阅服务器将接收事件,直到调用{@link#unregister(Object)}。
* 事件处理方法必须由{@link Subscribe}注释,必须是公共的,不返回任何内容(void),
* 并且只有一个参数(事件)。
*/
public class EventBus {
// 该方法必须在同步代码块中调用
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
// 获取订阅方法参数类型 , 可以是任意类型 , 自定义的 MessageEvent 消息类型
Class<?> eventType = subscriberMethod.eventType;
// Subscription 中封装了一个订阅者对象和一个订阅方法
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
// Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType 成员变量
// Key 是事件类型对象
// Value 是 Subscription 集合 , Subscription 中封装了一个订阅者对象和一个订阅方法
// 该 HashMap 的用途是保存当前的 eventType 对应的所有的订阅类和订阅方法
// 以便消息中心获取对应类型的消息后 , 可以顺利将其传递给相应订阅方法
// CopyOnWriteArrayList 是线程安全集合 , 写入数据的时候会拷贝一份出来 , 不会影响其它线程读取该集合的操作
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;
}
}
// Map<Object, List<Class<?>>> typesBySubscriber
// Key : 订阅者对象
// Value : 订阅方法参数类型集合
// 取消注册时 , 需要使用该方法
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
// 处理方法粘性相关业务逻辑
if (subscriberMethod.sticky) {
if (eventInheritance) {
// 必须考虑eventType的所有子类的现有粘性事件。
// 注意:迭代所有事件可能效率低下,因为有很多粘性事件,
// 因此,应更改数据结构以允许更高效的查找
// 例如,存储超类子类的附加映射:Class->List<Class>)。
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);
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
三、Subscription 类
Subscription 类中封装了一个订阅者对象和一个订阅方法
final class Subscription {
final Object subscriber;
final SubscriberMethod subscriberMethod;
}
- 1
- 2
- 3
- 4
文章来源: hanshuliang.blog.csdn.net,作者:韩曙亮,版权归原作者所有,如需转载,请联系作者。
原文链接:hanshuliang.blog.csdn.net/article/details/120444960
- 点赞
- 收藏
- 关注作者
评论(0)