EventBus 简介
EventBus 直译过来就是事件总线,熟悉计算机原理的人一定很熟悉总线的概念,所有设备都连接到总线上,然后在总线控制器上注册一个地址,当接收到消息的时候,总线控制器就从自己地址列表中取出该地址,把这个消息转发给某个设备。所以这个是个典型的应用了发布-订阅设计模式的开源库,它使用起来非常方便,同时使代码简洁,减少了模块之间的耦合。
EventBus使用方法
1. 加入到你的项目中
Gradle:
compile 'org.greenrobot:eventbus:3.0.0'
Maven:
<dependency>
<groupId>org.greenrobot</groupId>
<artifactId>eventbus</artifactId>
<version>3.0.0</version>
</dependency>
或者从Maven Center下载。
2. 基本概念:
在使用之前,有几个重要基本概念需要理解:
- Event
- Subscriber
- Publisher
下面这幅图说明了这几者之间的关系:
索引加速
我们在前面留了一个悬念,说EventBus 用了一项黑科技。上面的这个架构图中的右侧部分就是这项黑科技。使用索引加速后,能极大的提高索引速度,下面这张图来自作者的博客。
性能对比应用索引加速
前面介绍了这个黑科技多么牛X,相信你已经跃跃欲试了。那我们就开始来介绍怎么使用吧!
- 因为注解解析依赖于android-apt-plugin,所以我们首先在项目的 gradle 的 dependencies 中加入 apt 编译插件:
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
- 在 App 的 build.gradle 中应用apt插件,并设置apt生成的索引的包名和类名,eventBusIndex的值是由你指定的,编译成功后就会生成一个 MyEventBusIndex.java 文件:
apply plugin: 'com.neenbedankt.android-apt'
apt {
arguments {
eventBusIndex "com.daniex.demoApp.MyEventBusIndex"
}
}
- 接着我们在 App 的 dependencies 中引入 EventBusAnnotationProcessor :
apt 'org.greenrobot:eventbus-annotation-processor:3.0.1'
- 编译一次,就会在{ApplicationName}/build/generated/apt/{packagename} 目录下生成 MyEventBusIndex.java 。要应用我们刚刚生成的index,我们可以通过以下方法:
EventBus mEventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();
如果你不想每次都写这么冗长的代码,你可以在你的 application 类中把我们刚刚生成的索引设置为默认的:
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
在其他地方我们可以像平常一样用 EventBus.getDefault()
来获取默认实例了。
下面就是通过索引加速生成的代码:
/** This class is generated by EventBus, do not edit. */
public class EventBusIndex implements SubscriberInfoIndex {
private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;
static {
SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();
putIndex(new SimpleSubscriberInfo(com.dili.posandroid.activity.ChooseCategoryActivity.class, true,
new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onSelcted", com.dili.posandroid.event.CategorySelectEvent.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;
}
}
}
生成索引加速的原理,我们必须的看 EventBusAnnotationProcessor.java 源码:
@SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe")
@SupportedOptions(value = {"eventBusIndex", "verbose"})
public class EventBusAnnotationProcessor extends AbstractProcessor {
/** Found subscriber methods for a class (without superclasses). 被注解表示的方法信息 */
private final ListMap<TypeElement, ExecutableElement> methodsByClass = new ListMap<>();
private final Set<TypeElement> classesToSkip = new HashSet<>(); // checkHasErrors检查出来的异常方法
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
Messager messager = processingEnv.getMessager();
try {
String index = processingEnv.getOptions().get(OPTION_EVENT_BUS_INDEX);
if (index == null) { // 如果没有在gradle中配置apt的argument,编译就会在这里报错
messager.printMessage(Diagnostic.Kind.ERROR, "No option " + OPTION_EVENT_BUS_INDEX +
" passed to annotation processor");
return false;
}
/** ... */
collectSubscribers(annotations, env, messager); // 根据注解拿到所有订阅者的回调方法信息
checkForSubscribersToSkip(messager, indexPackage); // 筛掉不符合规则的订阅者
if (!methodsByClass.isEmpty()) {
createInfoIndexFile(index); // 生成索引类
}
/** 打印错误 */
}
/** 下面这些方法就不再贴出具体实现了,我们了解它们的功能就行 */
private void collectSubscribers // 遍历annotations,找出所有被注解标识的方法,以初始化methodsByClass
private boolean checkHasNoErrors // 过滤掉static,非public和参数大于1的方法
private void checkForSubscribersToSkip // 检查methodsByClass中的各个类,是否存在非public的父类和方法参数
/** 下面这三个方法会把methodsByClass中的信息写到相应的类中 */
private void writeCreateSubscriberMethods
private void createInfoIndexFile
private void writeIndexLines
}
结语
每当我们看到项目中 activity 之间,看到activity 跟 Fragment 、activity 跟adapter之间互相调用,强制转换,高度耦合,像一团乱麻的时候,心里总是忍不住骂一句:WTF ! EventBus 高效、简洁和极易入门的特性让人着迷。有了它,妈妈再也不会担心我写出像一坨翔一样的代码了。
网友评论