EventBus 3.0 源码分析

前言

EventBus是一个Android事件发布/订阅框架,通过解耦发布者和订阅者简化Android事件传递,这里的事件可以理解为消息。事件传递既可以用于Android四大组件间通讯,也可以用于异步线程和主线程间通讯等。
传统的事件传递方式包括:Handler、BroadcastReceiver、Interface回调,相比之下EventBus的优点是代码简洁,使用简单,并将事件发布和 订阅充分解耦

基本使用

建议阅读:EventBus使用详解&EventBus 中文文档&EventBus使用详解

初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}

public static EventBusBuilder builder() {
return new EventBusBuilder();
}

public EventBus() {
this(DEFAULT_BUILDER);
}

EventBus(EventBusBuilder builder) {
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
logSubscriberExceptions = builder.logSubscriberExceptions;
logNoSubscriberMessages = builder.logNoSubscriberMessages;
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
throwSubscriberException = builder.throwSubscriberException;
eventInheritance = builder.eventInheritance;
executorService = builder.executorService;
}

上面是 EventBus 初始化的三个步骤,直观上看用到单例模式和Builder模式,将构造参数给分离了出来,实际上还用到了策略模式,其中Builder中有些参数用于代码执行的策略,就说,你传的参数不一样,我执行的方式不一样,像 ignoreGeneratedIndex 作用就是让 EventBus 如何查找出订阅方法的策略。这些布尔类型的参数,在分析代码中可以逐步的了解到,先了解一些缓存对象,以更容易的了解源码:

  • subscriptionsByEventType : 内部是一个Map集合,可以根据 EventType 查找订阅事件。
  • typesBySubscriber : 根据我们的订阅对象找到 EventType,用于注册和注销。
  • stickyEvents : 粘性事件的缓存。
  • 事件投递者 : mainThreadPoster, backgroundPoster, asyncPoster 根据订阅注解 ThreadMode 去选择不同的投递者,不同投递者投递事件,接收函数会执行在不同的线程中。
  • subscriberMethodFinder :查找方法用的,内部维护了一个订阅方法的集合。

注册

1
2
3
4
5
6
7
8
9
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}

register(this)中中把订阅者传了进来,register(this)方法的执行主要分为两个步骤,第一个就是 findSubscriberMethods 找出一个 SubscriberMethod 的集合,然后就遍历 SubscriberMethod 将订阅者和订阅者事件处理注册到EventBus,首先看 findSubscriberMethods() 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
//缓存命中,直接返回
return subscriberMethods;
}
//是否忽略APT生成的索引带来的优化
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
//存入缓存并返回
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}

首先从缓存中查找订阅者的订阅事件处理方法,如果找到了就立马返回。如果缓存中没有的话,则根据 ignoreGeneratedIndex选择如何查找订阅方法,最后,找到订阅方法后,放入缓存,以免下次继续查找。ignoreGeneratedIndex默认就是false(是由创建EventBus的时候传递进去的Builder决定的,这个参数的含义是是否忽略编译的时候生成的索引,直接用反射的方式去获取事件订阅者的事件处理方法),那我们会执行 findUsingInfo() 方法,先分析findUsingInfo() 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
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);
}
// 会会会会继续查找父类的方法
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}

findUsingInfo() 方法的第一步是准备 FindState,prepareFindState()方法的源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
private FindState prepareFindState() {
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
if (state != null) {
FIND_STATE_POOL[i] = null;
return state;
}
}
}
return new FindState();
}

就是从对象池中拿出一个 FindState对象进行复用(节省了内存),FindState 中维护的是我们对订阅方法查找结果的封装。其实,往后面,我们就知道作者这里设计的非常精妙。第二步,initForSubscriber()就是将我们的订阅者传给FindState对象。第三步做的就是不断从订阅者和订阅者的父类去查找订阅方法,第三步的while循环中存在一个if判断,这里牵扯到EventBus 3.0提供的一个优化措施(前面讲到的ignoreGeneratedIndex变量如果设置为true就会忽略这个优化),后续进行讲解,这里我们只需要知道在我们没有进行任何设置的时候,默认是会执行findUsingReflectionInSingleClass()方法的,我们一起看下 findUsingReflectionInSingleClass():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
//getDeclaredMethods能拿到所有(不包括继承的方法)
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
// 事件处理方法必须为public,这里过滤掉所有非public方法
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
// 事件处理方法必须只有一个参数
if (parameterTypes.length == 1) {
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
//只有在子类中没有找到,才会添加到subscriberMethods
ThreadMode threadMode = subscribeAnnotation.threadMode();
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
// 如果某个方法加了@Subscribe注解,并且不是1个参数,则抛出EventBusException异常
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException("@Subscribe method " + methodName +
"must have exactly 1 parameter but has " + parameterTypes.length);
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
// 如果某个方法加了@Subscribe注解,并且不是public修饰,则抛出EventBusException异常
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}

代码主要逻辑就是对订阅者方法的遍历,看有没有注解,有的话就解析注解,最后将找到的订阅方法的集合封装到FindState对象中的subscriberMethods集合中。在解析添加了注解的方法的时候,有两种情况下会抛出异常,一个是添加了注解的方法不是pulic方法,另一个是添加了注解的方法的参数不只有一个,另外最终异常,会不会抛出还受到strictMethodVerification参数的限制,这个参数也是在构造EventBus的时候,由Builder决定的。另外,并不是所有的方法都会被添加到subscriberMethods集合中,在添加前会进行过滤,这个过滤是通过**checkAdd()**方法完成的,过滤主要针对以下的两种情况:

  • 对于同一个 Event,当前类对该对象使用了多个方法进行了多次订阅,那么如果该 Event 被发射的时候,当前类会如何调用这些方法?
  • 对于同一个 Event,父类对该对象进行了一次订阅,子类重写该订阅方法,那么如果该 Event 被发射的时候,父类子类当中会如何处理这些方法?

看下**checkAdd()**方法的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
boolean checkAdd(Method method, Class<?> eventType) {
// 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
// Usually a subscriber doesn't have methods listening to the same event type.
Object existing = anyMethodByEventType.put(eventType, method);
if (existing == null) {
return true;
} else {
if (existing instanceof Method) {
if (!checkAddWithMethodSignature((Method) existing, eventType)) {
// Paranoia check
throw new IllegalStateException();
}
// Put any non-Method object to "consume" the existing Method
anyMethodByEventType.put(eventType, this);
}
return checkAddWithMethodSignature(method, eventType);
}
}

可以看到 anyMethodByEventType使用了 Event 的 Class作为键,这像是意味着一个类对于同一个 Event 只能订阅一次,事实上是不是这样,还得继续看看checkAddWithMethodSignature(),其源码简化如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(method.getName());
methodKeyBuilder.append('>').append(eventType.getName());

String methodKey = methodKeyBuilder.toString();
Class<?> methodClass = method.getDeclaringClass();
Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
// Only add if not already found in a sub class
return true;
} else {
// Revert the put, old class is further down the class hierarchy
subscriberClassByMethodKey.put(methodKey, methodClassOld);
return false;
}
}

可以看到 subscriberClassByMethodKey使用方法名 + ‘>’ + 事件类型作为键,这意味着对于同一个类来说,subscriberClassByMethodKey 肯定不会键重复(毕竟一个类中不能够方法名相同且方法参数、个数都相同),因此它最终会返回 true。这意味着一个类如果使用了多个方法对同一个 Event 对象进行注册,那么当该 Event 对象被发射出来的时候,所有的方法都将会得到回调。

但是当父类执行上述操作的时候,如果子类有「显示」实现父类的订阅方法,那么第一次执行checkAddWithMethodSignature的时候subscriberClassByMethodKey.put(methodKey, methodClass) 返回值为空,方法返回true,在第二次执行checkAddWithMethodSignature的时候subscriberClassByMethodKey.put(methodKey, methodClass) 返回值不为空,且为当前方法所在类的子类,所以这时候会走入 if 下分支并返回 false。这意味着当子类「显示」实现父类的订阅方法的时候,如果此时发射指定 Event 的话,父类的订阅方法将不会执行,而仅会执行子类的订阅方法。

总结来说:

  • 如果当前类中,对同一个事件有多个订阅方法,那么这些方法都会执行,
  • 如果子类与父类中同时存在了相同事件处理函数,则父类中的不会被添加到subscriberMethods。

我们解析完了之后,在看findUsingInfo方法的最后,返回了getMethodsAndRelease(FindState)*,将我们的 FindState传给了getMethodsAndRelease()方法,getMethodsAndRelease()方法的源码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
findState.recycle();
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
if (FIND_STATE_POOL[i] == null) {
FIND_STATE_POOL[i] = findState;
break;
}
}
}
return subscriberMethods;
}

在解析完了之后,将订阅方法赋给List集合,再回收FindState,继续接收解析,内存没有半点浪费。最后,我们返回的是一个订阅方法的集合。这样,我们通过反射解析注解,找到订阅方法的方式,我们已经分析完了。接下来再看看通过apt处理器来查找事件处理方法,我们知道apt处理,是针对源码的处理,是执行在编译过程中的。所以性能要比反射好的多,所以推荐大家使用这种方式*。
如果我们配置使用了apt进行编译时处理那么findUsingInfo中**getSubscriberInfo(findState)**返回值就不会空了,这个时候就会执行后续的操作,可以看出后续操作没有任何反射操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
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);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}

**getSubscriberInfo(findState)**的源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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;
}
}
//从我们传入的MyEventBusIndex中查找是否存在订阅消息,订阅消息就是订阅方法,包括父类的订阅方法
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}

上面一段代码是针对缓存的,如果缓存中有就直接返回,底下,是从 subscriberInfoIndexes 中查找订阅信息的。subscriberInfoIndexes 是从构建EventBus的时候传递进去的EventBusBuilder对象中得到的:

1
2
3
4
5
6
7
8
9
10
11
12
13
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();

boolean logSubscriberExceptions = true;
boolean logNoSubscriberMessages = true;
boolean sendSubscriberExceptionEvent = true;
boolean sendNoSubscriberEvent = true;
boolean throwSubscriberException;
boolean eventInheritance = true;
boolean ignoreGeneratedIndex;
boolean strictMethodVerification;
ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
List<Class<?>> skipMethodVerificationForClasses;
List<SubscriberInfoIndex> subscriberInfoIndexes;

EventBusBuilder中subscriberInfoIndexes默认是空的,我们需要对Buidler进行设置。具体操作如下,修改build文件:

1
2
3
4
5
6
7
8
9
10
//在defaultConfig中加入如下的代码
defaultConfig {
javaCompileOptions{
annotationProcessorOptions{arguments=[eventBusIndex:'tk.thinkerzhangyan.myappli cation.MyEventBusIndex'] }
}
}
//在dependencies中加入如下的代码
dependencies {
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.0.1'
}

注意:Android Gradle插件2.2之前是使用apt的,2.2以后使用annotationProcessor代替了apt,建议阅读android-apt切换为官方annotationProcessor。javaCompileOptions这里是生成加速配置文件,MyEventBusIndex就是生成文件的名字,前面就是你的包名,编译之后可以查看:

此处输入图片的描述

MyEventBusIndex.java的源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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("onDoEventOne", MainActivity.MyEvent.class),
}));

putIndex(new SimpleSubscriberInfo(Main2Activity.class, true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onDoEvent", MainActivity.MyEvent.class, ThreadMode.POSTING, 0, true),
}));

}

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初始化,将这个类给传进去:

1
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus().register(this);

这样getSubscriberInfo方法就会返回SubscriberInfo对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
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);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}

findUsingInfo方法中

1
2
3
4
5
6
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}

代码就得到了执行,需要强调的是,我们是在编译过程中就已经找到我们的订阅信息了,不会在运行期做任何事情,所以这个效率是非常高的。这样通过apt处理器来查找事件处理方法也分析完了,接下来再看看,当ignoreGeneratedIndex参数设置为true的时候,当这个参数设置为true的时候,会忽略apt优化设置,这时候会执行findUsingReflection(subscriberClass)去查找当订阅类的事件处理方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}

if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}

findUsingReflection(subscriberClass)方法的源码如下所示:

1
2
3
4
5
6
7
8
9
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findUsingReflectionInSingleClass(findState);
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}

findUsingReflection(subscriberClass)方法和我们之前分析的findUsingReflectionInSingleClass(FindState findState)的逻辑基本是一样的,这里就不分析了。接下来继续分析register代码中的subscribe(subscriber, subscriberMethod)方法。

订阅

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
// 获取订阅了某种类型数据的Subscription。使用了CopyOnWriteArrayList,这个是线程//安全的,CopyOnWriteArrayList会在更新的时候,重新生成一份copy,其他线程使用的是copy,///不存在什么线程安全性的问题。
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
if (subscriptions.contains(newSubscription)) {
//如果已经被注册过了,则抛出EventBusException异常
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}

int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
//根据优先级将newSubscription查到合适位置
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
//将处理事件类型添加到typesBySubscriber
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);

// 如果该事件处理方法为粘性事件,即设置了“sticky=true”,则需要调用checkPostStickyEvent//ToSubscription判断是否有粘性事件需要处理,如果需要处理则触发一次事件处理函数
if (subscriberMethod.sticky) {
if (eventInheritance) {
// Existing sticky events of all subclasses of eventType have to be considered.
// Note: Iterating over all events may be inefficient with lots of sticky events,
// thus data structure should be changed to allow a more efficient lookup
// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}

订阅的代码主要就做了两件事,第一件事情就是将我们的订阅方法和订阅者,封装到subscriptionsByEventType和typesBySubscriber。这两者的作用是什么?前者的作用,当我们投递订阅事件的时候,就会根据我们的 EventType从subscriptionsByEventType中找到我们的订阅事件,从而去分发事件,处理事件,具体的实现后面会讲到;后者的作用,是在调用unregister(this)的时候,根据订阅者从typesBySubscriber中找到我们的EventType,又根据我们的EventType从typesBySubscriber中找到找到订阅事件,从而解绑用的,解绑的代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}

subscribe方法中做的第二件事,就是如果方法是处理粘性事件的话,就立马投递、执行相应的粘性事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if (subscriberMethod.sticky) {
if (eventInheritance) {
// Existing sticky events of all subclasses of eventType have to be considered.
// Note: Iterating over all events may be inefficient with lots of sticky events,
// thus data structure should be changed to allow a more efficient lookup
// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}

可以看到在执行处理粘性事件的方法的之前会根据eventInheritance进行判断,eventInheritance参数的含义是是否允许事件继承,这个参数也是由构建EventBus的时候,传递进去的Builder决定的,默认是true。当使用EventBus的时候如果我们的Event之间存在继承关系,可以将该字段设为 false 以提高性能。如果设置为true,这个事件的所有子事件,都会被post。不管是否允许事件继承,都会执行checkPostStickyEventToSubscription(newSubscription, stickyEvent)方法,这个方法的源码如下所示:

1
2
3
4
5
6
7
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
if (stickyEvent != null) {
// If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)
// --> Strange corner case, which we don't take care of here.
postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
}
}

方法中调用了postToSubscription触发该事件的事件处理函数。postToSubscription函数后面讲post时会讲到。

发布

调用EventBus的post方法来发布事件,post方法的源码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/** Posts the given event to the event bus. */
public void post(Object event) {
//每个线程中都维护了一个投递的状态
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);

// 确保不会被调用多次
if (!postingState.isPosting) {
//标识post的线程是否是主线程
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
//循环处理eventQueue中的每一个event对象
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
//处理完之后重置postingState的一些标识信息
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}

currentPostingThreadState 是一个 ThreadLocal 类,通过它获取到 PostingThreadState 对象,再根据该对象获取到 event 链表(有没有联想到 Android 中的消息机制?),并将传入的 event 塞入该链表。PostingThreadState的定义:

1
2
3
4
5
6
7
8
9
10
/** For ThreadLocal, much faster to set (and get multiple values). */
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<Object>();
boolean isPosting;
boolean isMainThread;
Subscription subscription;
Object event;
boolean canceled;
}

主要是有个成员eventQueue,由于是ThreadLocal,所以结果就是,每个线程有一个PostingThreadState对象,这个对象内部有一个事件的队列,并且有一个成员isPosting表示现在是否正在派发事件,当发送事件开始时,会依次取出队列中的事件发送出去,如果正在派发事件,那么post直接把事件加入队列后返回,还有个成员isMainThread,这个成员在实际派发事件时会用到,在postSingleEvent中会用到。
为了控制高并发下的一个 Event 回调不会被调用多次,利用PostingThreadState对象的isPosting 来标记当前链表是否已经开始进行回调操作,通过源码可以看到,每次分发完一个Event事件,该事件也会被从链表中remove出去,代码中调用了postSingleEvent方法来发布事件,postSingleEvent源码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
// 如果允许事件继承,则会调用lookupAllEventTypes查找所有的父类和接口类
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
//如果post的事件没有被注册,则post一个NoSubscriberEvent事件
post(new NoSubscriberEvent(this, event));
}
}
}

在postSingleEvent方法中,我们又见到了前面已经分析了的eventInheritance变量,这里先分析eventInheritance变量为false的情况,当eventInheritance变量为false的时候,会执行postSingleEventForEventType(event, postingState, eventClass)进行事件分发,这个方法的源码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}

通过 subscriptionsByEventType获取该Event事件对应的订阅信息链表,然后将该订阅信息、Event 和当前线程信息传给了 postToSubscription()方法,该方法是用来回调所有订阅方法的,该方法的源码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
// 如果该事件处理函数没有指定线程模型或者线程模型为PostThread
// 则调用invokeSubscriber在post的线程中执行事件处理函数
invokeSubscriber(subscription, event);
break;
case MAIN:
// 如果该事件处理函数指定的线程模型为MainThread并且当前post的线程为主线程//,则调用invokeSubscriber在当前线程(主线程)中执行事件处理函数如果post的线程不是主线///程,将使用mainThreadPoster.enqueue该事件处理函数添加到主线程的消息队列中
if (isMainThread) {
//当前是主线程,那就直接调用订阅函数
invokeSubscriber(subscription, event);
} else {
//当前是子线程,通过handler实现在主线程中执行
mainThreadPoster.enqueue(subscription, event);
}
break;
case BACKGROUND:
// 如果该事件处理函数指定的线程模型为BackgroundThread并且当前post的线程为主//线程,则调用backgroundPoster.enqueue如果post的线程不是主线程,则调用invokeSubscriber///在当前线程(非主线程)中执行事件处理函数
if (isMainThread) {
//当前是主线程,创建一个runnable丢到线程池里面
backgroundPoster.enqueue(subscription, event);
} else {
//当前是子线程,直接调用
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
// //添加到异步线程队列中,,,,不论什么线程,直接丢入线程池
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}

该方法主要是根据register注册的事件处理函数的线程模型在指定的线程中触发事件处理函数。关于EventBus的线程模型的概念,不明白的可以自己去查阅,这里就不讲解了。mainThreadPoster、backgroundPoster和asyncPoster分别是HandlerPoster、BackgroundPoster和AsyncPoster的对象,其中HandlerPoster继承自Handler,BackgroundPoster和AsyncPoster继承自Runnable。

接下来分析下这三个类,首先看下HandlerPoster,mainThreadPoster是在EventBus的构造函数中初始化的。

1
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);

在EventBus的构造函数中,我们看到mainThreadPoster初始化的时候,传入的是Looper.getMainLooper()。所以此Handle是运行在主线程中的。HandlerPoster的源码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
final class HandlerPoster extends Handler {

private final PendingPostQueue queue;
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
private boolean handlerActive;

HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
super(looper);
this.eventBus = eventBus;
this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
queue = new PendingPostQueue();
}

void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}

@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
PendingPost pendingPost = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
}

HandlerPoster继承自Handler,有四个成员变量:

1
2
3
4
private final PendingPostQueue queue;//一个队列,用来存放PendingPost
private final int maxMillisInsideHandleMessage;//handleMessage方法的执行的最长时间
private final EventBus eventBus;//当前的EventBus对象
private boolean handlerActive;//handleMessage方法是否在执行中

PendingPostQueue是一个队列,用来存放PendingPost,而PendingPost中维护的是事件Event和处理事件的Subscription,PendingPost源码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
final class PendingPost {
private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>();

Object event;
Subscription subscription;
PendingPost next;

private PendingPost(Object event, Subscription subscription) {
this.event = event;
this.subscription = subscription;
}

static PendingPost obtainPendingPost(Subscription subscription, Object event) {
synchronized (pendingPostPool) {
int size = pendingPostPool.size();
if (size > 0) {
PendingPost pendingPost = pendingPostPool.remove(size - 1);
pendingPost.event = event;
pendingPost.subscription = subscription;
pendingPost.next = null;
return pendingPost;
}
}
return new PendingPost(event, subscription);
}

static void releasePendingPost(PendingPost pendingPost) {
pendingPost.event = null;
pendingPost.subscription = null;
pendingPost.next = null;
synchronized (pendingPostPool) {
// Don't let the pool grow indefinitely
if (pendingPostPool.size() < 10000) {
pendingPostPool.add(pendingPost);
}
}
}

}

PendingPost的构造方法是私有的,不能通过构造方法来创建PendingPost,PendingPost提供了obtainPendingPost和releasePendingPost来完成PendingPost的复用(没有的时候创建)和回收,这种实现使得内存得到了充分的利用。

当调用enqueue()方法时,会把这个事件加入队列中,如果当前没在派发消息就向自身发送Message触发handleMessage方法的执行。在handleMessage中会依次取出队列中的消息交由EventBus直接调用事件处理函数,而handleMessage执行所在的线程就是构造函数中传进来的Looper所属的线程,在EventBus中构造mainThreadPoster时传进来的是MainLooper,所以会在UI线程中执行。

解下来看下BackgroundPoster。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
final class BackgroundPoster implements Runnable {

private final PendingPostQueue queue;
private final EventBus eventBus;

private volatile boolean executorRunning;

BackgroundPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new PendingPostQueue();
}

public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!executorRunning) {
executorRunning = true;
eventBus.getExecutorService().execute(this);
}
}
}

@Override
public void run() {
try {
try {
while (true) {
PendingPost pendingPost = queue.poll(1000);
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
executorRunning = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}

}

BackgroundPoster实现了Runnable接口,成员变量:

1
2
3
4
private final PendingPostQueue queue;
private final EventBus eventBus;

private volatile boolean executorRunning;

executorRunning用来标示run方法是否在执行中,通过这个变量,使得BackgroundPoster实现了单线程模式,当调用enqueue()方法时,会把这个事件加入队列中,如果executorRunning为false,说明BackgroundPoster没有在运行中,那么就会调用eventBus.getExecutorService()返回一个cache线程池来运行BackgroundPoster,如果executorRunning为true,说明BackgroundPoster在运行中,这个时候只会将事件加入到队列中,而不会开启新的线程去处理事件。当长时间无事件时BackgroundPoster所属的线程被会销毁,下次再Post事件时再创建新的线程。

我们可以看到run方法中会依次取出队列中的事件进行处理,由于所有的事件都是在一条线程中处理的,所以如果一个线程模式为BACKGROUND的事件处理方法中发生了阻塞,将会导致其他的事件处理方法得不到执行,我们要避免这种情况的发生

最后再来看下AsyncPoster:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class AsyncPoster implements Runnable {

private final PendingPostQueue queue;
private final EventBus eventBus;

AsyncPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new PendingPostQueue();
}

public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
queue.enqueue(pendingPost);
eventBus.getExecutorService().execute(this);
}

@Override
public void run() {
PendingPost pendingPost = queue.poll();
if(pendingPost == null) {
throw new IllegalStateException("No pending post available");
}
eventBus.invokeSubscriber(pendingPost);
}

}

AsyncPoster和BackgroundPoster是类似的,只不过每次调用他的enqueue()方法时候,除了会将事件插入到队列中外,都会开启一个新的线程来处理事件,所以不会出现一个方法阻塞,导致其他方法得不到执行的情况,这也是AsyncPoster和BackgroundPoster不同的地方。

这时候再回过头去看postToSubscription方法就没什么问题了,最后再看下invokeSubscriber(subscription, event)方法:

1
2
3
4
5
6
7
8
9
10
void invokeSubscriber(Subscription subscription, Object event) {
try {
//通过反射调用事件处理函数
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}

代码很简单,就是通过反射调用事件处理方法,来处理相应的事件,invokeSubscriber(pendingPost)是类似的。

1
2
3
4
5
6
7
8
 void invokeSubscriber(PendingPost pendingPost) {
Object event = pendingPost.event;
Subscription subscription = pendingPost.subscription;
PendingPost.releasePendingPost(pendingPost);
if (subscription.active) {
invokeSubscriber(subscription, event);
}
}

这样,当不允许事件继承的时候,调用post方法发送事件的流程,我们分析完了,接下来再看看允许事件继承的时候,调用post方法发送事件的流程,回到postSingleEvent方法,当允许事件继承的时候,以下的代码会得到执行:

1
2
3
4
5
6
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}

当允许事件继承的时候,首先会调用lookupAllEventTypes方法来得到当前发送事件的所有父类事件类型,然后循环调用postSingleEventForEventType来发送事件(postSingleEventForEventTyp源码前面分析过了,这里就不再做分析了)这样,所有注册到EventBus的处理当前事件的父类事件的方法,都会被调用,用来处理当前的事件。看下lookupAllEventTypes(eventClass)的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {
synchronized (eventTypesCache) {
List<Class<?>> eventTypes = eventTypesCache.get(eventClass);
if (eventTypes == null) {
eventTypes = new ArrayList<>();
Class<?> clazz = eventClass;
while (clazz != null) {
eventTypes.add(clazz);
addInterfaces(eventTypes, clazz.getInterfaces());
clazz = clazz.getSuperclass();
}
eventTypesCache.put(eventClass, eventTypes);
}
return eventTypes;
}
}

就是查找当前事件的所有父类型的事件,然后将当前事件的类型和所有父类事件的类型,都添加到eventTypesCache缓存起来,方便后续的使用。

到这里为止,通过post发布事件的整个流程代码就已经分析完了。

粘性事件

项目中如果想要发射 sticky 事件需要通过 EventBus#postSticky() 方式,源码如下:

1
2
3
4
5
6
7
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
post(event);
}

可以看到第一步是将该事件放入 stickyEvents 中,第二步则是正常 post()。为避免多线程操作 postSticky(Object) 和 removeStickyEvent(Class<?>) 引发的冲突,所以对 stickyEvents 对象添加了 synchronized关键字。前文在讲解EventBus#register()方法的时候已经对该方法中关于sticky事件的处理,进行过讲解,这里就不再叙述了。

EventBus中各个类的介绍

盗用的类图

此处输入图片的描述

EventBus

EventBus类负责所有对外暴露的API,其中的register()、post()、unregister()函数配合上自定义的EventType及事件响应函数即可完成核心功能。
EventBus默认可通过静态函数getDefault获取单例,当然有需要也可以通过’EventBusBuilder’或 构造函数新建一个EventBus,每个新建的EventBus发布和订阅事件都是相互隔离的,即一个EventBus对象中的发布者发布事件,另一个EventBus对象中的订阅者不会收到该订阅。

EventBusBuilder

跟一般Builder类似,用于在需要设置参数过多时构造EventBus。包含的属性也是EventBus的一些设置参数。build函数用于新建EventBus对象,installDefaultEventBus函数将当前设置应用于Default EventBus。

SubscriberMethodFinder

订阅者响应函数信息存储和查找类,上面具体分析过了,主要用于查找订阅者响应函数,如果不在缓存中,则遍历自己的每个函数并递归父类查找,查找成功后保存到缓存中。

SubscriberMethod

订阅者事件响应函数信息,包括响应方法、线程Mode、事件类型以及一个用来比较SubscriberMethod是否相等的特征值methodString,共四个变量。

Subscription

订阅者信息,包括subscriber对象、事件响应方法SubscriberMethod、优先级priority。

HandlerPoster

事件主线程处理,对应ThreadMode.MainThread。继承自Handler,enqueue函数将事件放到队列中,并利用handler发送message,handleMessage函数从队列中取事件,invoke事件响应函数处理。

AsyncPoster

事件异步线程处理,对应ThreadMode.Async,继承自Runnable。enqueue函数将事件放到队列中,并调用线程池执行当前任务,在run函数从队列中取事件,invoke事件响应函数处理。

BackgroundPoster

事件Background处理,对应ThreadMode.BackgroundThread,继承自Runnable。enqueue函数将事件放到队列中,并调用线程池执行当前任务,在run函数从队列中取事件,invoke事件响应函数处理。与AsyncPoster不同的是,BackgroundPoster中的任务只在同一个线程中依次执行,而不是并发执行。

PendingPost

订阅者和事件信息实体类,并含有同一队列中指向下一个对象的指针。通过缓存存储不用的对象,减少下次创建的性能消耗。

PendingPostQueue

通过head和tail指针维护一个PendingPost队列。HandlerPoster、AsyncPoster、BackgroundPoster都包含一个此队列实例,表示各自的订阅者及事件信息队列,在事件到来时进入队列,处理时从队列中取出一个元素进行处理。

SubscriberExceptionEvent

当调用事件处理函数异常时发送的EventBus内部自定义事件,通过post发送,订阅者可自行订阅这类事件进行处理。

NoSubscriberEvent

当没有事件处理函数对事件处理时发送的EventBus内部自定义事件,通过post发送,订阅者可自行订阅这类事件进行处理。

EventBusException

封装于’RuntimeException’之上的Exception,只是覆盖构造函数,相当于一个标记,标记是属于EventBus的Exception。

ThreadMode

线程模式枚举类,表示事件响应函数执行线程信息,包括ThreadMode.PostThread、ThreadMode.MainThread、ThreadMode.BackgroundThread、ThreadMode.Async四种。

总结

优化

eventInheritance

当使用EventBus的时候如果我们的Event之间存在继承关系,可以将该字段设为 false 以提高性能。

APT

EventBus 内部使用了大量的反射去寻找接收事件方法,实际上有经验的小伙伴知道可以使用 APT 来优化。这也就是EventBus 3.0引入的技术,代码中通过ignoreGeneratedIndex来判断是否使用生成的APT代码去优化寻找接收事件的过程,如果开启了的话,那么将会通过subscriberInfoIndexes来快速得到接收事件方法的相关信息。如果没有在项目中接入 EventBus 的APT,那么可以将ignoreGeneratedIndex设为 false 提高性能。

设计技巧

设计模式

利用了单例模式,Builder模式和策略模式。

反射方法

EventBus 在获取接收事件方法的信息中,通过getDeclaredMethods()来获取类中所有方法而并不是通过 getMethods(),由于前者只反射当前类的方法(不包括隐式继承的父类方法),所以前者的效率较后者更高些。

FindState

以下代码是 FindState 的获取:

1
2
3
4
5
6
7
8
9
10
11
12
private FindState prepareFindState() {
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
if (state != null) {
FIND_STATE_POOL[i] = null;
return state;
}
}
}
return new FindState();
}

以下代码是 FindState 的回收复用:

1
2
3
4
5
6
7
8
9
10
11
12
13
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
findState.recycle();
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
if (FIND_STATE_POOL[i] == null) {
FIND_STATE_POOL[i] = findState;
break;
}
}
}
return subscriberMethods;
}

可以看到,EventBus 使用 FindState 并不是简单的 new,由于 FindState 在注册流程中使用频繁且创建耗费资源,故创建 FindState 池复用 FindState 对象,与此相同的还有 PendingPost,它用于反射调用接收事件方法,具体不在此扩展。

版本区别

2.2以后添加的订阅事件处理方法必须是公共方法,2.2以前没有这个要求;
3.0以后订阅事件处理方法使用了注解,3.0以前没使用注解;

扩展,如何自定义Android注解库

创建一个Module,在这个Module里面自定义注解,然后创建一个Module,在这个Modlue里面自定义注解处理器放。

自定义注解处理器的时候,常用到两个库:auto-service和javapoet

  • auto-service自动用于在META-INF/services目录文件夹下创建javax.annotation.processing.Processor文件;

  • javapoet用于产生 .java 源文件的辅助库,它可以很方便地帮助我们生成需要的.java 源文件。

auto-service使用很简单,只需要在定义的注解处理器上添加@AutoService(Processor.class)即可,示例如下:

1
2
3
4
@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor {
....
}

如果不使用auto-service,需要我们自己手动的在相应的目录下创建相关的文件。步骤如下:
1、在 processors 库的 main 目录下新建 resources 资源文件夹;
2、在 resources文件夹下建立 META-INF/services 目录文件夹;
3、在 META-INF/services 目录文件夹下创建 javax.annotation.processing.Processor 文件;
4、在 javax.annotation.processing.Processor 文件写入注解处理器的全称,包括包路径;

此处输入图片的描述

这个文件的作用,就是告诉jvm(或者是编译器)我们自己定义的注解处理器的位置。如果没有这个文件的话,我们的注解处理器是根本不会起作用的。

关于javapoet的使用,请查阅API。

前面我们提到,需要将自定义的注解和注解解析器放在两个不同的Module里面,之所以将注解和注解处理器放在两个不同的Module里面,主要是因为,只有在编译的时候需要这个注解处理器,而在打包APK的时候这个注解处理器是不需要打包进APK里面的,所以我们单独给注解处理器建了一个Module。

注解处理器只在编译处理期间需要用到,编译处理完后就没有实际作用了,而主项目添加了这个库会引入很多不必要的文件,为了处理这个问题我们需要引入个插件android-apt,它能很好地处理这个问题。

它有两个目的:

  • 允许配置只在编译时作为注解处理器的依赖,而不添加到最后的APK或library
  • 设置源路径,使注解处理器生成的代码能被Android Studio正确的引用
1
伴随着 Android Gradle 插件 2.2 版本的发布,android-apt 作者在官网发表声明证实了后续将不会继续维护 android-apt,并推荐大家使用 Android 官方插件提供的相同能力。也就是说,大约三年前推出的 android-apt 即将告别开发者,退出历史舞台,Android Gradle 插件提供了名为 annotationProcessor 的功能来完全代替 android-apt。

annotationProcessor的功能和android-apt的功能是一样的。这里我们只介绍annotationProcessor的使用。

在工程中使用我们自定义的注解,需要在工程中依赖包含我们自定义注解的Module,为了使用我们自定义的注解解析器处理我们自定义的注解,需要借助于annotationProcessor。这些都可以通过配置gradle文件来完成,附录使用eventbus的gradle文件。

1
2
3
4
5
dependencies {
compile 'org.greenrobot:eventbus:3.0.0'
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.0.1'
}

依赖自定义的注解库:

1
compile 'org.greenrobot:eventbus:3.0.0'

借助于annotationProcessor依赖,自定义的注解处理处理器:

1
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.0.1'

Android 注解指南

自定义注解之编译时注解(RetentionPolicy.CLASS)(一)(建议先看这个系列)
自定义注解之编译时注解(RetentionPolicy.CLASS)(二)——JavaPoet
自定义注解之编译时注解(RetentionPolicy.CLASS)(三)—— 常用接口介绍

android-apt切换为官方annotationProcessor

Android」Android开发你需要知道的注解(Annotation)

Android进阶之自定义注解(建议看这个)
如何自定义 Android 注解?
Android,几分钟教你怎么应用自定义注解

参考链接:

源码地址:
GitHub地址
GitHub地址-带中文注解(新)
GitHub地址-带中文注解(旧)

如何使用(新版本):
eventbus
EventBus使用详解
EventBus使用详解
EventBus使用详解
EventBus 中文文档

如何使用(老版本):
EventBus使用详解(一)——初步使用EventBus
EventBus使用详解(二)——EventBus使用进阶

源码解析:
EventBus 3.0源码解析
聊一聊 EventBus 源码和设计之禅
事件分发框架——EventBus浅析
EventBus源码解析
进击的巨人——EventBus源码解析(老版本)

快速Android开发系列通信篇之EventBus
EventBus - 1 核心概念:事件传递/EventBus的优点/传统handler通信的两种方式(更新中)
Eventbus3代码分析(六):SubscriberMethodFinder类

相关Java知识:
getMethods 与 getDeclaredMethods 的区别

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器