EventBusEventBus 源码解析 ( 注册订阅者 | 订阅方法 | 查找订阅方法 )
Posted 韩曙亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了EventBusEventBus 源码解析 ( 注册订阅者 | 订阅方法 | 查找订阅方法 )相关的知识,希望对你有一定的参考价值。
文章目录
一、EventBus 注册订阅者
EventBus 中调用 EventBus.getDefault().register(this)
注册订阅者 ; 该方法中主要进行了如下
2
2
2 个步骤 :
- ① 获取 订阅者 集合 , 查找当前订阅类中符合条件的订阅方法集合 ;
- ② 遍历 订阅者 集合 , 进行事件订阅 , 保存数据 , 这些数据就是一些映射关系
/**
* EventBus是Java和android的中央发布/订阅事件系统。
* 事件被发布({@link#post(Object)})到总线,总线将其传递给具有匹配处理程序的订阅者
* 事件类型的方法。
* 要接收事件,订阅者必须使用{@link#register(Object)}将自己注册到总线。
* 一旦注册,订阅服务器将接收事件,直到调用{@link#unregister(Object)}。
* 事件处理方法必须由{@link Subscribe}注释,必须是公共的,不返回任何内容(void),
* 并且只有一个参数(事件)。
*/
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);
}
}
}
}
二、订阅方法
SubscriberMethod
对订阅的方法进行了一些封装 , 包括了方法的 Method 对象 Method method
, 线程模式 ThreadMode threadMode
, 事件类型 Class<?> eventType
, 优先级 int priority
, 粘性 boolean sticky
等 ;
/** 由EventBus内部使用并生成订户索引。 */
public class SubscriberMethod {
final Method method;
final ThreadMode threadMode;
final Class<?> eventType;
final int priority;
final boolean sticky;
/** Used for efficient comparison */
String methodString;
}
三、查找订阅方法 findSubscriberMethods 方法
订阅方法缓存机制 : 从缓存中获取 订阅方法 , METHOD_CACHE
缓存是一个 HashMap
集合 ;
如果订阅者有很多方法 , 如果每次订阅都要查询所有的方法 , 如果遍历一次 Activity 的所有方法 很消耗性能 ; 因此这里引入了缓存机制 ;
第一次订阅时 , 将方法都放在缓存集合中 , 如果第二次订阅 , 不用再次查找方法 ;
如果缓存中没有订阅方法 , 那么说明这是第一次查找订阅方法 , 一般情况下都是调用 subscriberMethods = findUsingInfo(subscriberClass)
方法 , 获取订阅方法 ;
class SubscriberMethodFinder {
// 方法缓存集合
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
// 从缓存中获取 订阅方法 , METHOD_CACHE 缓存是一个 HashMap 集合
// 如果订阅者有很多方法 , 如果每次订阅都要查询所有的方法 , 很消耗性能
// 第一次订阅时 , 将方法都放在集合中
// 如果第二次订阅 , 不用再次查找方法
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
// 如果缓存中没有订阅方法 , 那么说明这是第一次查找订阅方法
// ignoreGeneratedIndex 属性默认是 false
// 是否忽略注解生成器
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
// 一般情况下 , 调用的是该方法
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
}
下面分析 findUsingInfo
方法 ;
四、查找订阅方法 findUsingInfo 方法
FindState 是辅助类 , 其中进行了状态保存等信息 ;
参数 Class<?> subscriberClass
是订阅者类 , 将订阅类设置到 FindState 查找状态类对象中 ;
该方法的核心是调用了 findUsingReflectionInSingleClass(findState)
方法 , 进行后续查找操作 ;
class SubscriberMethodFinder {
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
// FindState 是辅助类 , 其中进行了状态保存等信息
FindState findState = prepareFindState();
// 将订阅类设置到 FindState 查找状态类对象中
findState.initForSubscriber(subscriberClass);
// 订阅类的字节码类
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
// 从 查找状态 中 获取订阅信息 , 如果订阅信息不为空 , 进行如下处理
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else { // 从 查找状态 中 获取订阅信息 , 如果订阅信息为空 , 进行如下处理
findUsingReflectionInSingleClass(findState);
}
// 查找订阅类的上级父类 , 继续进行循环
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
}
五、查找订阅方法 findUsingReflectionInSingleClass
通过反射获取订阅者类中的所有方法 , 遍历 订阅者 类中的所有方法 , 过滤掉不符合条件的方法 , 将符合条件的方法封装到 findState.subscriberMethods 集合中 ;
过滤方案 :
- 订阅方法的参数个数肯定只有 1 个 ;
- 订阅方法上有 @Subscribe 注解 ;
- @Subscribe 注解属性判断 ;
- @Subscribe 注解线程模式判断 ;
class SubscriberMethodFinder {
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// 通过反射获取订阅者类中的所有方法
// 这比getMethods快,特别是当订阅者是像 Activity 这样的大类时
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
}
// 遍历 订阅者 类中的所有方法 , 过滤掉不符合条件的方法 ,
for (Method method : methods) {
int modifiers = method.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
// 订阅方法的参数个数肯定只有 1 个
if (parameterTypes.length == 1) {
// 订阅方法上有 @Subscribe 注解
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
// @Subscribe 注解属性判断
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
// @Subscribe 注解线程模式判断
ThreadMode threadMode = subscribeAnnotation.threadMode();
// 将符合条件的方法封装到 findState.subscriberMethods 集合中 ;
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
}
}
}
}
}
以上是关于EventBusEventBus 源码解析 ( 注册订阅者 | 订阅方法 | 查找订阅方法 )的主要内容,如果未能解决你的问题,请参考以下文章
EventBusEventBus 源码解析 ( 注册订阅者 | 订阅方法 | 查找订阅方法 )
EventBusEventBus 源码解析 ( 事件发送 | 线程池中执行订阅方法 )
EventBusEventBus 源码解析 ( 事件发送 | postToSubscription 方法 | EventBus 线程模式处理细节 )
EventBusEventBus 源码解析 ( 事件发送 | EventBus.post 方法 | EventBus.postSingleEvent 方法 )
EventBusEventBus 源码解析 ( 注册订阅者总结 | 从封装的数据结构角度分析 EventBus )
EventBusEventBus 源码解析 ( 事件发送 | 发布线程为 子线程 切换到 主线程 执行订阅方法的过程分析 )