在EventBus源码解析中的findUsingInfo方法中有说到如果没有配置索引类,那么就会调用findUsingReflectionInSingleClass方法,在运行时利用反射来获取所有被@Subscribe注解
标注的订阅方法,但这种做法对应用性能会有一定的损耗,所以在3.0后EventBus提供了索引来提高应用运行效率。
首先,在app下的build.gradle添加依赖和对应的配置:
apply plugin: 'kotlin-kapt'
dependencies {
...
implementation 'org.greenrobot:eventbus:3.1.1'
kapt 'org.greenrobot:eventbus-annotation-processor:3.1.1'
}
kapt {
arguments {
// 指定索引类的全路径名
arg('eventBusIndex', 'com.ljw.eventbus_index.MyEventBusIndex')
}
}
在Activity编写个测试的订阅方法:
@Subscribe
public fun doSomething(singleEvent: SingleEvent){
println("singleEvent: ${singleEvent.value}")
}
在编译期间会通过注解处理器去查找使用@Subscribe注解
标注的方法,生成一个实现了SubscriberInfoIndex接口的类:
/** 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>();
// SubscriberMethodInfo方法包含了方法名、事件类型等信息
// 在编译时期获取到所有的订阅信息,并且保存在Map中
putIndex(new SimpleSubscriberInfo(MainActivity.class, true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("doSomething", SingleEvent.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;
}
}
}
在该索引类中获取所有的订阅信息,保存到Map中,再看下SimpleSubscriberInfo内的处理:
public class SimpleSubscriberInfo extends AbstractSubscriberInfo {
private final SubscriberMethodInfo[] methodInfos;
public SimpleSubscriberInfo(Class subscriberClass, boolean shouldCheckSuperclass, SubscriberMethodInfo[] methodInfos) {
super(subscriberClass, null, shouldCheckSuperclass);
this.methodInfos = methodInfos;
}
@Override
public synchronized SubscriberMethod[] getSubscriberMethods() {
int length = methodInfos.length;
SubscriberMethod[] methods = new SubscriberMethod[length];
for (int i = 0; i < length; i++) {
SubscriberMethodInfo info = methodInfos[i];
methods[i] = createSubscriberMethod(info.methodName, info.eventType, info.threadMode,
info.priority, info.sticky);
}
return methods;
}
}
protected SubscriberMethod createSubscriberMethod(String methodName, Class<?> eventType, ThreadMode threadMode,
int priority, boolean sticky) {
try {
// 通过方法名和事件类型获取到Method对象
Method method = subscriberClass.getDeclaredMethod(methodName, eventType);
// 构造订阅方法并返回
return new SubscriberMethod(method, eventType, threadMode, priority, sticky);
} catch (NoSuchMethodException e) {
throw new EventBusException("Could not find subscriber method in " + subscriberClass +
". Maybe a missing ProGuard rule?", e);
}
}
可以看到,生成的索引类主要是保存了订阅类与它所有的订阅信息的映射,外部通过getSubscriberInfo就能获取到对应订阅类的订阅信息。回到EventBus源码解析#findUsingInfo方法这里:
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
... 省略部分代码
// 循环直到findState的clazz为空(clazz为java.或android.或javax.等系统类则结束查找)
while (findState.clazz != null) {
// 由于subscriberInfoIndexes()为空,则该方法就返回null
// subscriberInfoIndexes(注解处理器生成的索引类),通过EventBus.builder().addIndex(索引类)添加进来
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);
}
// 将clazz指向订阅类的父类,直到找到java.或android.或javax.等系统类,则返回null
findState.moveToSuperclass();
}
// 获取订阅方法集合并释放FindState
return getMethodsAndRelease(findState);
}
private SubscriberInfo getSubscriberInfo(FindState findState) {
... 省略代码
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}
在有配置索引类的情况下,这里通过调用getSubscriberInfo就能获取到订阅者的所有的订阅方法信息。subscriberInfoIndexes是在构造方法传入的,所以使用索引的话需要使用EventBus.builder().addIndex(MyEventBusIndex()).installDefaultEventBus()来创建EventBus对象。