源码细节阅读
上一节根据EventBus的使用流程把实现源码大体梳理了一遍,因为精力有限,所以看源码都是根据实现过程把基本流程看下,中间实现细节先忽略,否则越看越深不容易把握大体思路,这节把一些细节的部分再看看。
一、注解函数查找源码逻辑
#EventBus
public void register(Object subscriber) {
Class> subscriberClass = subscriber.getClass();
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
在进行注册的时候,我们使用subscriberMethodFinder
对象的findSubscriberMethods
方法来查找到所有该类中以@Subscribe
注解的函数(以下简称为注解函数)。让我们继续看下查找部分的逻辑。
List findSubscriberMethods(Class> subscriberClass) {
List subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
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;
}
}
METHOD_CACHE
是一个ConcurrentHashMap
类型的常量,用来保存subscriberClass
和对应SubscriberMethod
的集合,以提高注册效率,防止重复查找。
如果METHOD_CACHE
缓存中不存在,判断变量ignoreGeneratedIndex
的值,该值是在EventBusBuilder
中初始化的,表示是否忽略注解生成器,默认是false
。然后会进入到findUsingInfo
函数中进行查找(下面再看),最后将找到的subscriberMethods
添加到METHOD_CACHE
中。
private List findUsingInfo(Class> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
````
return getMethodsAndRelease(findState);
}
先看findUsingInfo
前两行,出现一个FindState
类,它是SubscriberMethodFinder
的内部类,用来辅助查找订阅事件的方法。
private FindState prepareFindState() {
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
if (state != null) {
FIND_STATE_POOL[i] = null;
return state;
}
}
}
return new FindState();
}
static class FindState {
```
void initForSubscriber(Class> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
}
prepareFindState()
方法主要是返回一个FindState
对象,先从FIND_STATE_POOL
这个缓存池中获取一个现成的,如果没有就新建一个对象。获取对象后调用初始化方法,将subscriberClass
赋值给clazz
变量,subscriberInfo
对象赋值为null
。
private List findUsingInfo(Class> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
```
} else {
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
再回到findUsingInfo
,因为findState.clazz
刚赋值过,所以不为空。再来看下getSubscriberInfo
方法。
private SubscriberInfo getSubscriberInfo(FindState findState) {
if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
if (findState.clazz == superclassInfo.getSubscriberClass()) {
return superclassInfo;
}
}
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}
前面执行initForSubscriber
的时候,subscriberInfo
赋值为null
,因此第一个if
不成立。第二个判断是对象subscriberInfoIndexes
,该变量也是在EventBusBuilder
中初始化的,默认是null
,因此该方法返回值null
。
private List findUsingInfo(Class> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
```
} else {
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
再回到findUsingInfo
,由于getSubscriberInfo
返回为null
,逻辑会走到findUsingReflectionInSingleClass
方法中,使用反射来获取所有方法(下面再看)。
获取当前类所有的注解方法后,findState.moveToSuperclass()
表示修改findState.clazz
为subscriberClass
的父类Class
,继续遍历父类中的注解方法。
private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
```
}
for (Method method : methods) {
int modifiers = method.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
Class> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException("@Subscribe method " + methodName +
"must have exactly 1 parameter but has " + parameterTypes.length);
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}
上面代码流程如下:
- 通过方法
getDeclaredMethods()
获取该类中所有声明的方法列表; - 遍历方法列表,获取方法的修饰符,如果修饰符是
public
并且不是abstract
、static
等进入下一步,MODIFIERS_IGNORE
定义如第一行代码; - 获取方法的参数列表,如果参数的个数是1,并且使用了
Subscribe
注解,获取唯一的入参进行下一步; - 然后
checkAdd()
方法用来判断FindState的anyMethodByEventType map
是否已经添加过以当前eventType
为key
的键值对,没添加过则返回true
(就是看看当前类中有没有多个事件相同的注解函数); - 通过注解对象
subscribeAnnotation
获取threadMode
,然后新建SubscriberMethod
添加到findState.subscriberMethods
集合中。
分析完findUsingReflectionInSingleClass
这个方法后,我们回到findUsingInfo
。
private List findUsingInfo(Class> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
```
} else {
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
遍历当前类及其父类,通过findUsingReflectionInSingleClass
方法找到所有注解方法后,通过getMethodsAndRelease
返回所有相关方法。
private List getMethodsAndRelease(FindState findState) {
List subscriberMethods = new ArrayList<>(findState.subscriberMethods);
findState.recycle();
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
if (FIND_STATE_POOL[i] == null) {
FIND_STATE_POOL[i] = findState;
break;
}
}
}
return subscriberMethods;
}
通过上面的解析知道,所有的SubscriberMethod
都添加到findState.subscriberMethods
集合中,这个方法就是把findState.subscriberMethods
集合中的内容复制出来,然后释放findState
中的资源,并把findState
放到FIND_STATE_POOL
缓存中,POOL_SIZE
常量是4,这样下次查找的时候可以重复利用无需每次都新建对象。
以上为注解方法查找的过程。在上面分析的过程中出现了两个变量subscriberInfoIndexes
和ignoreGeneratedIndex
看样子都是关于索引的,分析的时候都是使用的EventBusBuilder
中的默认值。看下subscriberInfoIndexes
赋值的地方,看注释意思是:将EventBus
注解处理器生成索引添加添加进来。所以注解处理器需要再了解下。
/** Adds an index generated by EventBus' annotation preprocessor. */
public EventBusBuilder addIndex(SubscriberInfoIndex index) {
if (subscriberInfoIndexes == null) {
subscriberInfoIndexes = new ArrayList<>();
}
subscriberInfoIndexes.add(index);
return this;
}
二、Subscriber Index注解处理器
通过上面分析可知,EventBus
注册事件时,主要是在项目运行时通过反射来查找注解方法信息,如果项目中有大量的注解方法,必然会对项目运行时的性能产生影响。
除了在项目运行时通过反射查找注解方法信息,EventBus
还提供了在项目编译时通过注解处理器查找注解方法信息的方式,生成一个辅助的索引类来保存这些信息,这个索引类就是Subscriber Index。
1、Subscriber Index使用方式
首先要在 app
的build.gradle
中加入如下配置:
android {
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
// 指定辅助索引类的名称和包名,注意,这个类时自动生成的,不需要我们写
arguments = [ eventBusIndex : 'com.jane.demo.MyEventBusIndex' ]
}
}
}
}
dependencies {
compile 'org.greenrobot:eventbus:3.3.1'
// 引入注解处理器
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.3.1'
}
在项目的Application
中添加如下配置,以生成一个默认的EventBus
单例:
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
此时重新编译下项目,会生成一个MyEventBusIndex
类(不同的gradle
版本生成的位置可能不一样)。
生成的MyEventBusIndex
代码如下:
public class MyEventBusIndex implements SubscriberInfoIndex {
private static final Map, SubscriberInfo> SUBSCRIBER_INDEX;
static {
SUBSCRIBER_INDEX = new HashMap, SubscriberInfo>();
putIndex(new SimpleSubscriberInfo(EventBusService.class, true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onMsgEventReceived", String.class),
new SubscriberMethodInfo("onMsgEventReceived", MsgEvent.class),
new SubscriberMethodInfo("onMsgEventReceived", org.greenrobot.eventbus.NoSubscriberEvent.class),
}));
putIndex(new SimpleSubscriberInfo(EventBusActivity.class, true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onMsgEventReceived", Event.class),
}));
}
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;
}
}
}
代码中SUBSCRIBER_INDEX
是一个HashMap
,保存了当前注册类的Class
类型和其中注解方法的信息。
2、Subscriber Index源码
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
使用的时候,获取EventBusBuilder
对象,然后调用addIndex
方法,把生成的MyEventBusIndex
加入进去。
/** Adds an index generated by EventBus' annotation preprocessor. */
public EventBusBuilder addIndex(SubscriberInfoIndex index) {
if (subscriberInfoIndexes == null) {
subscriberInfoIndexes = new ArrayList<>();
}
subscriberInfoIndexes.add(index);
return this;
}
上面的方法是不是比较眼熟,就是上面代码分析的时候出现的变量subscriberInfoIndexes
赋值函数。这样,运行的时候就把之前编译好的索引类的实例保存在subscriberInfoIndexes
集合中。然后调用installDefaultEventBus
方法创建EventBus
实例。
/**
* Installs the default EventBus returned by {@link EventBus#getDefault()} using this builders' values. Must be
* done only once before the first usage of the default EventBus.
*
* @throws EventBusException if there's already a default EventBus instance in place
*/
public EventBus installDefaultEventBus() {
synchronized (EventBus.class) {
if (EventBus.defaultInstance != null) {
throw new EventBusException("Default instance already exists." +
" It may be only set once before it's used the first time to ensure consistent behavior.");
}
EventBus.defaultInstance = build();
return EventBus.defaultInstance;
}
}
/** Builds an EventBus based on the current configuration. */
public EventBus build() {
return new EventBus(this);
}
上面通过build
方法,以当前EventBusBuilder
对象作为参数生成EventBus
单例对象,并赋值给defaultInstance
,这样就把subscriberInfoIndexes
信息传递给了EventBus
。以后调用EventBus
的getDefault()
返回的就是这里生成的单例对象,里面包含了subscriberInfoIndexes
信息。
而且在Application
中生成了EventBus
的默认单例,这样就保证了在项目其它地方执行EventBus.getDefault()
就能得到就是上面包含subscriberInfoIndexes
信息的单例。
在上面分析查找注解函数的时候,分析过一个函数:
private List findUsingInfo(Class> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
····
} else {
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
如果没有使用注解处理器的话getSubscriberInfo
这个方法返回值是null
,因此会走到findUsingReflectionInSingleClass
,通过反射区获取注解方法。现在使用使用注解处理器的话在重新看下这个函数。
private SubscriberInfo getSubscriberInfo(FindState findState) {
if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
if (findState.clazz == superclassInfo.getSubscriberClass()) {
return superclassInfo;
}
}
//不为空
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}
@Override
public SubscriberInfo getSubscriberInfo(Class> subscriberClass) {
SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
if (info != null) {
return info;
} else {
return null;
}
}
如果使用了注解处理器,因为subscriberInfoIndexes
这个集合不为空,遍历获取当前类对应的注解方法列表,index.getSubscriberInfo
这个方法实际调用的就是系统生成的MyEventBusIndex
中的getSubscriberInfo
方法,这样就获取到了之前编译生成的注解方法。
private List findUsingInfo(Class> subscriberClass) {
FindState findState = prepareFindState();
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);
}
通过getSubscriberInfo
返回当前类所有注解方法后,遍历所有订阅了事件的方法然后加入到subscriberMethods
列表中,其它的和之前的注册流程一样。
参考文章:
EventBus 原理解析