前言
EventBus是一种用于Android的发布/订阅事件总线。它有很多优点:简化应用组件间的通信;解耦事件的发送者和接收者;避免复杂和容易出错的依赖和生命周期的问题;很快,专门为高性能优化过等等。
基础知识
EventBus的基础知识和使用详解可以阅读这篇文章:EventBus使用详解
源码分析
EventBus源码分析主要分为两个过程:
- 订阅事件
- 发布事件
在分析订阅事件之前,我们先来分析一下与订阅事件相关的订阅者索引。
订阅者索引
默认情况下,EventBus使用Java反射来查找订阅者信息。订阅者索引是EventBus 3的一个新特性。它可以加速查找订阅者信息的过程,是一个可选的优化。订阅者索引的原理是:使用EventBus的注解处理器在应用构建期间创建订阅者索引类,该类已经包含了所有的订阅者信息。EventBus官方推荐在Android中使用订阅者索引以获得最佳的性能。
要开启订阅者索引的生成,你需要在构建脚本中使用annotationProcessor属性将EventBus的注解处理器添加到应用的构建中,还要设置一个eventBusIndex参数来指定要生成的订阅者索引的完全限定类名。
首先,修改模块下的build.gradle构建脚本。如下所示:
android {
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = [eventBusIndex: 'com.github.cyc.eventbus.subscriberindexdemo.MyEventBusIndex']
}
}
}
...
}
dependencies {
...
compile 'org.greenrobot:eventbus:3.1.1'
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1'
}
然后,build一下工程。EventBus注解处理器将为你生成一个订阅者索引类。示例代码如下所示:
package com.github.cyc.eventbus.subscriberindexdemo;
import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;
import org.greenrobot.eventbus.meta.SubscriberMethodInfo;
import org.greenrobot.eventbus.meta.SubscriberInfo;
import org.greenrobot.eventbus.meta.SubscriberInfoIndex;
import org.greenrobot.eventbus.ThreadMode;
import java.util.HashMap;
import java.util.Map;
/** 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>();
putIndex(new SimpleSubscriberInfo(MainActivity.class, true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onMessageEvent", MessageEvent.class, ThreadMode.MAIN),
}));
}
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静态成员变量中。后面查找订阅者信息时,EventBus就可以直接调用getSubscriberInfo()方法来获取该订阅者的信息了。
最后,在应用自定义的Application类的onCreate()方法中将订阅者索引添加到EventBus中,并将该EventBus设置成默认的EventBus。示例代码如下所示:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// 配置EventBus
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
}
}
我们来看builder()、addIndex()和installDefaultEventBus()方法的代码:
public class EventBus {
static volatile EventBus defaultInstance;
...
public static EventBusBuilder builder() {
return new EventBusBuilder();
}
}
public class EventBusBuilder {
...
List<SubscriberInfoIndex> subscriberInfoIndexes;
public EventBusBuilder addIndex(SubscriberInfoIndex index) {
if (subscriberInfoIndexes == null) {
subscriberInfoIndexes = new ArrayList<>();
}
subscriberInfoIndexes.add(index);
return this;
}
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;
}
}
public EventBus build() {
return new EventBus(this);
}
}
builder()静态方法新建了一个EventBusBuilder对象。addIndex()方法将生成的订阅者索引添加到EventBusBuilder对象的subscriberInfoIndexes成员变量中。installDefaultEventBus()方法调用了build()方法新建了一个EventBus对象,并将该对象赋值给EventBus的defaultInstance静态成员变量。这样,后面调用EventBus.getDefault()静态方法获取到的就是该EventBus对象了。我们接着来看EventBus.getDefault()静态方法的代码:
public class EventBus {
static volatile EventBus defaultInstance;
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
private final Map<Object, List<Class<?>>> typesBySubscriber;
private final Map<Class<?>, Object> stickyEvents;
private final Poster mainThreadPoster;
private final BackgroundPoster backgroundPoster;
private final AsyncPoster asyncPoster;
private final SubscriberMethodFinder subscriberMethodFinder;
...
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus(