前言
在上篇文章 Android 注解系列之 EventBus3 原理(四)中我们讲解了 EventBus3 的内部原理,在该篇文章中我们将讲解 EventBus3 中的 “加速引擎"
---索引类。阅读该篇文章我们能够学到如下知识点。
- EventBus3 索引类出现的原因
- EventBus3 索引类的使用
- EventBus3 索引类生成的过程
- EventBus3 混淆注意事项
对 APT 技术不熟悉的小伙伴,可以查看文章 Android-注解系列之APT工具(三)
前景回顾
在 Android 注解系列之 EventBus3 原理(四)中,我们特别指出在 EventBus3 中优化了 SubscriberMethodFinder
获取类中包含 @Subscribe
注解的订阅方法的流程。使其能在 EventBus.register()
方法调用之前就能知道相关订阅事件的方法,这样就减少了程序在运行期间使用反射遍历获取方法所带来的时间消耗。优化点如下图中 红色虚线框
所示:
EventBus 作者 Markus Junginger 也给出了使用索引类前后 EventBus 的效率对比,如下图所示:
从上图中,我们可以使用索引类后,EventBus 的效率有着明显的提升,而效率提升的背后,正是使用了 APT
技术所创建的索引类
。那么接下来我们就来看一看 EventBus3 中是如何结合 APT
技术来进行优化的。
关键代码
阅读过 EventBus3 源码的小伙伴应该都知道,在 EventBus3 中获取类中包含 @Subscribe
注解的订阅方法有两种方式。
- 第一种:是直接在程序运行时反射获取
- 第二种:就是通过索引类。
而使用索引类的关键代码为 SubscriberMethodFinder
中的
getSubscriberInfo() 方法与 findUsingInfo() 方法 。
我们分别来看这两个方法。
findUsingInfo 方法
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//?关键代码,从索引类中获取 SubscriberInfo
findState.subscriberInfo = getSubscriberInfo(findState);
//方式1:如果 subscriberInfo 不为空,则从该对象中获取 SubscriberMethod 对象
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 {
//方式2:如果 subscriberInfo 为空,那么直接通过反射获取
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
我们能从该方法中获得以下信息:
- EventBus3 中默认会调用 getSubscriberInfo() 方法去获取 subscriberInfo 对象信息。
- 如果 subscriberInfo 不为空,则会从该对象中获取
SubscriberMethod
数组。 - 如果 subscriberInfo 为空,那么会直接通过
反射
去获取SubscriberMethod
集合信息。
SubscriberMethod 类中含有
@Subscribe
注解的方法信息封装(优先级,是否粘性,线程模式,订阅的事件),以及当前方法的 Method 对象(java.lang.reflect
包下的对象)。
也就说 EventBus 是否通过反射获取信息,是由 getSubscriberInfo()方法来决定,那么我们查看该方法。
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;
}
}
//?这里是EventBus3中优化的关键,索引类
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);