前言 EventBus使用起来还是很方便的,它的源码是基于反射实现的,在3.0之后增加了注解处理器,在程序的编译时候,就可以根据注解生成相对应的代码,相对于之前的直接通过运行时反射,大大提高了程序的运行效率,但是在3.0默认的还是通过反射去查找用@Subscribe
标注的方法,一般在使用的时候基本都是这个模式
//注册
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this)
}
//反注册
if (EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().unregister(this)
}
虽然用起来还是很方便的,但是这种默认就是通过反射去查找在代码中注册的方法,这就在性能上有一定的损耗。所以通过这些时读
EventBus3.0
的源码的一点感悟,来谈谈注解处理器中SubscriberInfoIndex
在EventBus3.0
的使用SubscriberInfoIndex 【#|EventBus中SubscriberInfoIndex的使用】
EventBus
的注册和发送事件的源码执行过程就不再这里讲了,这篇文章就讲得蛮清楚的Android开源框架源码鉴赏:EventBus一般获取它的实例就是通过
EventBus.getDefault()
获取,看源码很明显就是一个静态单例的实现,但是我要说的是它的构造方法就是public
的,说明外界就可以直接通过new EventBus
获取其实例,而它的构造方法有一个EventBus(EventBusBuilder builder) {
....
}
这样的重载,这里我们就重点关注下
EventBusBuilder
,看到它其实就可以联想到EventBus
类可以通过Builder
构建者模式获取其实例文章图片
从这里就可以证明。
List subscriberInfoIndexes;
在
EventBusBuilder
中有这样一个变量,通过这个变量可以去使用注解处理器生成的代码。SubscriberInfoIndex
就是一个接口,而注解生成器生成的类也是继承的它,我们也可以自己去继承它,定制自己的需求,不需要反射的EventBus。在
EventBus
的源码中有这样一段代码//SubscriberMethodFinder
List findSubscriberMethods(Class> subscriberClass) {
....
//ignoreGeneratedIndex默认为false,我们可以设置为true,忽略SubscriberInfoIndex的代码
if (ignoreGeneratedIndex/*false*/) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
//走这一步
}
...
}private List findUsingInfo(Class> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
//默认为null
...
}
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;
}
如果subscriberInfoIndexes不为null,就会去调用SubscriberInfoIndex的getSubscriberInfo方法获取SubscriberInfo,SubscriberInfo这个变量就封装了注册方法的信息。看到这里,再来看官方提供给我们的例子
- 1.) 官方Demo
public class EventBusIndexTest {
private String value;
/** Ensures the index is actually used and no reflection fall-back kicks in. */
@Test
public void testManualIndexWithoutAnnotation() {
SubscriberInfoIndex index = new SubscriberInfoIndex() {@Override
public SubscriberInfo getSubscriberInfo(Class> subscriberClass) {
Assert.assertEquals(EventBusIndexTest.class, subscriberClass);
SubscriberMethodInfo[] methodInfos = {
new SubscriberMethodInfo("someMethodWithoutAnnotation", String.class)
};
return new SimpleSubscriberInfo(EventBusIndexTest.class, false, methodInfos);
}
};
EventBus eventBus = EventBus.builder().addIndex(index).build();
eventBus.register(this);
eventBus.post("Yepp");
eventBus.unregister(this);
Assert.assertEquals("Yepp", value);
}public void someMethodWithoutAnnotation(String value) {
this.value = https://www.it610.com/article/value;
}
}
Demo首先实例化了一个
SubscriberInfoIndex
匿名内部类,并且实现了getSubscriberInfo
方法。在这个方法中创建了一个SubscriberMethodInfo
数组,SubscriberMethodInfo
封装了方法名,当前线程,参数的事件类型,优先级,是否是粘性事件,然后将SubscriberMethodInfo
数组封装到SimpleSubscriberInfo
中,参数名分别为当前类名的class
, 是否应该检查父类,SubscriberMethodInfo
数组,SimpleSubscriberInfo
是SubscriberInfo
的实现类,最后将SimpleSubscriberInfo
的实例化结果作为getSubscriberInfo
的返回值。到这里就构成了一个
index
,然后就去通过构建者模式获取EventBus
的实例,剩下用法就和之前的一样的1.index在EventBus内部其实就是添加到了subscriberInfoIndexes
集合上,前面我们也看到在EventBus
内部会判断subscriberInfoIndexes
是否为null, 不为null直接获取里面封装的方法信息。这样就可以避免反射的影响。
2.我们也可以不必使用@Subscribe注解了
- 2.) 注解处理器中的SubscriberInfoIndex
EventBus3.0
增加了注解处理器,关于注解处理器我看了这篇文章比较详细。看完之后再来看EventBus
的注解处理器这个模块应该有帮助。有个地方需要提下的就是下图文章图片
我们需要在build文件中配置
OPTION_EVENT_BUS_INDEX
,不然后面的不会执行,至于怎么配,看官方的一个demo文章图片
javaCompileOptions {
annotationProcessorOptions {
arguments = [ eventBusIndex : 'org.greenrobot.eventbus.EventBusTestsIndex' ]
}
}
模板代码直接复制就可以了。看下生成的类文件
/** This class is generated by EventBus, do not edit. */
public class EventBusTestsIndex implements SubscriberInfoIndex {
private static final Map, SubscriberInfo> SUBSCRIBER_INDEX;
static {
SUBSCRIBER_INDEX = new HashMap, SubscriberInfo>();
putIndex(new SimpleSubscriberInfo(EventBusAndroidOrderTest.class, true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onEvent", String.class, ThreadMode.MAIN),
new SubscriberMethodInfo("onEvent", EventBusAndroidOrderTest.OrderedEvent.class, ThreadMode.MAIN_ORDERED),
}));
....}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;
}
}
}
基本就是这种模式,然后我们就可以通过
EventBus.builder().addIndex(index).build()
这种形式去获取EventBus
的实例,这样就可以避免大量反射在EventBus
中使用造成的性能损耗。总结 到了这里基本就完了,可以看到注解处理器还是很有用的,无论在
EventBus
,还是ButterKnife
中都有广泛的使用,所以注解处理器这方面还是要多学习下的。另外,我们不能只是简单停留在Api
级别的使用上,对于一些开源框架更深入的基本的原理还是需要掌握的,这样可以更好的使用它们,而不总是写些模板代码,学会了这些框架的设计思想,将它们运用到我们的项目中还是很有帮助的。推荐阅读
- 数据结构和算法|LeetCode 的正确使用方式
- #|7.分布式事务管理
- #|算法设计与分析(Java实现)——贪心算法(集合覆盖案例)
- #|算法设计与分析(Java实现)—— 动态规划 (0-1 背包问题)
- #|阿尔法点亮LED灯(一)汇编语言
- #|Multimedia
- #|ARM裸机开发(汇编LED灯实验(I.MX6UL芯片))
- 基础课|使用深度优先搜索(DFS)、广度优先搜索(BFS)、A* 搜索算法求解 (n^2 -1) 数码难题,耗时与内存占用(时空复杂度)对比(附((n^2 - 1) 数码问题控
- #|学习笔记 | Ch05 Pandas数据清洗 —— 缺失值、重复值、异常值
- win10|搏一搏 单车变摩托,是时候捣鼓一下家中的小米电视机啦。