事件分发框架——EventBus浅析

简介及基本概念

EventBus是Android下一个开源的注册分发(publish/subscrib)事件总线,主要功能是简化了Android各组件以及后台线程之间的相互通信。
常见的比如网络请求返回通知UI,两个Fragment之间通信等,都可以通过EventBus实现。
EventBus主要包括三个元素:

  • Event:事件
  • Subscriber:事件订阅者,接收特定的事件
  • Publisher:事件发布者,用于通知Subscriber有事件发生

Event

又可以称为消息,其实就是一个Object,意味着可以是任何对象,随意定义,可以是网络请求返回的字符串,也可以是一个开关状态等。

Subscriber

要进行事件订阅,就需要在类中实现以onEvent开头的函数,函数名包括onEventonEventMainThreadonEventBackgroundThreadonEventAsync这四个,具体使用跟ThreadMode有关,这个下文有阐述。

Publisher

可以在任意线程任意位置发送任意事件,直接调用EventBus的post(Object)即可。根据post函数的参数类型,会自动调用订阅相关Event的函数。

ThreadMode

EventBus共包括4个ThreadMode,分别是:

  • MainThread,对应方法onEventMainThread(),代表方法会在UI线程执行
  • PostThread,对应方法onEventPostThread(),代表方法会在当前发布事件的线程执行
  • BackgroundThread,对应方法onEventBackgroundThread(),代表方法如果是在非UI线程发布的事件,则直接执行,和发布在同一个线程中。如果在UI线程发布的事件,则加入后台任务队列,使用线程池一个接一个调用
  • Async,对应方法onEventAsync(),代表方法加入后台任务队列,使用线程池调用,注意没有BackgroundThread中的一个接一个

基本使用

根据官网,基本使用包括以下三步:

  1. 定义事件

    1
    public class MessageEvent { /* Additional fields if needed */ }
  2. 建立订阅者

    1
    2
    eventBus.register(this);
    public void onEvent(AnyEventType event) {/* Do something */};
  3. 事件分发

    1
    eventBus.post(event);

源码解析

核心变量

先来看看几个核心的Map:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// EventType -> List<? extends EventType>,事件到它的父事件列表的映射。即缓存一个类的所有父类
private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<Class<?>, List<Class<?>>>();

// EventType -> List<Subscription>,事件到订阅对象之间的映射
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
// Subscriber -> List<EventType>,订阅源到它订阅的的所有事件类型的映射
private final Map<Object, List<Class<?>>> typesBySubscriber;
// stickEvent事件,一般不太用
private final Map<Class<?>, Object> stickyEvents;

/*
* CopyOnWriteArrayList:
* 在CopyOnWriteArrayList里处理写操作(包括add、remove、set等)是先将原始的数据通过JDK1.6的Arrays.copyof()来生成一份新的数组,
* 然后在新的数据对象上进行写,写完后再将原来的引用指向到当前这个数据对象(这里应用了常识1),
* 这样保证了每次写都是在新的对象上(因为要保证写的一致性,这里要对各种写操作要加一把锁,JDK1.6在这里用了重入锁),
* 然后读的时候就是在引用的当前对象上进行读(包括get,iterator等),
* CopyOnWriteArrayList适合使用在读操作远远大于写操作的场景里,比如缓存
*/

register

注册分发的具体流程首先从注册开始看,register对外暴露了4个方法,分别是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void register(Object subscriber) {
register(subscriber, false, 0);
}

public void register(Object subscriber, int priority) {
register(subscriber, false, priority);
}

public void registerSticky(Object subscriber) {
register(subscriber, true, 0);
}

public void registerSticky(Object subscriber, int priority) {
register(subscriber, true, priority);
}

可以看到,针对不同的参数,提供了不同的register方法,这3个参数分别是:

  1. subscriber,订阅者,常见是Android组件。
  2. sticky,粘性,如果sticky为true,那么当事件发布之后,再有订阅者开始订阅该类型事件的话,就依然能收到该类型事件最近的一个sticky事件,一般用不上,默认false。有的时候,比如位置信息,时间信息,新注册的时间可能用得上。
  3. priority,优先级,优先级高的订阅者可以取消事件继续向优先级低的订阅者分发,默认所有订阅者优先级都为0。

真正的register内部实现是:

1
2
3
4
5
6
private synchronized void register(Object subscriber, boolean sticky, int priority) {
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod, sticky, priority);
}
}

可以看到,首先通过一个findSubscriberMethods方法去找到这个订阅者的所有订阅方法,返回一个List
来看看findSubscriberMethods

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
// 通过订阅者类名定义一个key
String key = subscriberClass.getName();
List<SubscriberMethod> subscriberMethods;
synchronized (methodCache) {
// 判断是否有缓存
subscriberMethods = methodCache.get(key);
}
if (subscriberMethods != null) {
// 有缓存直接返回缓存,第一次进的话肯定为null
return subscriberMethods;
}
subscriberMethods = new ArrayList<SubscriberMethod>();
Class<?> clazz = subscriberClass;
HashMap<String, Class> eventTypesFound = new HashMap<String, Class>();
StringBuilder methodKeyBuilder = new StringBuilder();
while (clazz != null) {
String name = clazz.getName();
// 过滤掉系统类
if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
// Skip system classes, this just degrades performance
break;
}

// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
try {
// 通过反射获取订阅者的所有方法,注意这边用getDeclaredMethods()而不是getMethods(),能少获取很多无用的方法
// This is faster than getMethods, especially when subscribers a fat classes like Activities
Method[] methods = clazz.getDeclaredMethods();
// 过滤出onEvent开头的方法
filterSubscriberMethods(subscriberMethods, eventTypesFound, methodKeyBuilder, methods);
} catch (Throwable th) {
th.printStackTrace();
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
Method[] methods = subscriberClass.getMethods();
subscriberMethods.clear();
eventTypesFound.clear();
filterSubscriberMethods(subscriberMethods, eventTypesFound, methodKeyBuilder, methods);
break;
}
// 还会遍历父类的订阅函数
clazz = clazz.getSuperclass();
}
// 最后加入缓存,第二次使用直接从缓存取
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called "
+ ON_EVENT_METHOD_NAME);
} else {
synchronized (methodCache) {
methodCache.put(key, subscriberMethods);
}
return subscriberMethods;
}
}

private void filterSubscriberMethods(List<SubscriberMethod> subscriberMethods,
HashMap<String, Class> eventTypesFound, StringBuilder methodKeyBuilder,
Method[] methods)
{

for (Method method : methods) {
String methodName = method.getName();
// 只获取onEvent开头的方法
if (methodName.startsWith(ON_EVENT_METHOD_NAME)) {
int modifiers = method.getModifiers();
Class<?> methodClass = method.getDeclaringClass();
// 判断订阅函数是否是public的,并且是否有修饰符
// 看来订阅函数只能是public的,并且不能被final,static等修饰
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
// 获取订阅函数的参数
Class<?>[] parameterTypes = method.getParameterTypes();
// 参数只能有1个
if (parameterTypes.length == 1) {
// 根据onEvent后面的部分获取ThreadMode
ThreadMode threadMode = getThreadMode(methodClass, method, methodName);
if (threadMode == null) {
continue;
}
// 获取参数类型,其实就是接收事件的类型
Class<?> eventType = parameterTypes[0];
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(methodName);
methodKeyBuilder.append('>').append(eventType.getName());
String methodKey = methodKeyBuilder.toString();
Class methodClassOld = eventTypesFound.put(methodKey, methodClass);
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
// Only add if not already found in a sub class
// 封装一个订阅方法对象,这个对象包含Method对象,threadMode对象,eventType对象
subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));
} else {
// Revert the put, old class is further down the class hierarchy
eventTypesFound.put(methodKey, methodClassOld);
}
}
} else if (!skipMethodVerificationForClasses.containsKey(methodClass)) {
Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + methodClass + "."
+ methodName);
}
}
}
}

关于findSubscriberMethods,我们要注意两点:

  1. 所有事件处理方法必需是public void类型的,并且只有一个参数表示EventType
  2. findSubscriberMethods不只查找Subscriber内的事件处理方法,同时还会查到它的继承体系中的所有基类中的事件处理方法

重回register方法,获取到了Subscriber的订阅函数之后,就要对每个找到的订阅函数调用subscribe进行注册了。

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
60
61
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {
// 从订阅方法中获得订阅的事件类型
Class<?> eventType = subscriberMethod.eventType;
// 通过订阅事件类型,找到所有的订阅(Subscription),订阅中包含了订阅者和订阅方法
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
// 创建一个新的订阅
Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);
if (subscriptions == null) {
// 如果该事件没有订阅列表,就创建一个并加入该订阅
subscriptions = new CopyOnWriteArrayList<Subscription>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
// 如果已有订阅列表,检查是否已经加入过
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}

// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
// subscriberMethod.method.setAccessible(true);

// 根据优先级插入订阅
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
if (i == size || newSubscription.priority > subscriptions.get(i).priority) {
subscriptions.add(i, newSubscription);
break;
}
}

// 将这个订阅事件加入到订阅者的订阅事件列表中
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<Class<?>>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);

// 对粘性事件的处理
if (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);
}
}
}

这里subscribe方法主要干了3件事情:

  1. 根据SubscriberMethod中的EventType类型将Subscribtion对象存放在subscriptionsByEventType中。建立EventTypeSubscription的映射,每个事件可以有多个订阅者。
  2. 根据SubscriberEventType存放在typesBySubscriber中,建立SubscriberEventType的映射,每个Subscriber可以订阅多个事件。
  3. 如果是Sticky类型的订阅者,直接向它发送上个保存的事件(如果有的话)。

通过SubscriberEventType的映射,我们就可以很方便地使一个Subscriber取消接收事件,而通过EventTypeSucscribtion的映射,可以方便地将相应的事件发送到它的每一个订阅者。

总结,register(this)就是去当前类遍历所有的方法,找到onEvent开头的然后进行存储

post

看完了register,现在来看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
/** 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) {
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
while (!eventQueue.isEmpty()) {
// 事件分发
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}

可以看到post内使用了PostingThreadState的对象,并且是ThreadLocal,来看PostingThreadState的定义:

1
2
3
4
5
6
7
8
9
/** 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中会用到。
接着在post函数里面往下看,可以看到,事件分发主要是在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
26
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
// 找到eventClass对应的事件,包含父类对应的事件和接口对应的事件
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);
}

// 如果没有订阅发现,那么会Post一个NoSubscriberEvent事件
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}

eventInheritance是什么?先不管,往里面看。

  1. 第一步是一个lookupAllEventTypes函数,这个函数的作用是把这个类的类对象、实现的接口及父类的类对象存到一个List中返回
  2. 第二步就是遍历第一步获取到的List了,对List中的每一个对象执行第三步。
  3. 第三步就是找到这个事件类型的所有订阅者向其发送事件。

这样我们就懂得了eventInheritance的含义了。如果为true,当我们Post一个事件时,这个事件的父事件(事件类的父类的事件)也会被Post,所以如果有个事件订阅者接收Object类型的事件,那么它就可以接收到所有的事件
eventInheritance默认为true,可以在EventBus的构造器EventBusBuilder里面设置。
上面说的第三步就是真正的事件分发了:

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
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
// 找到订阅事件对应的订阅,这个是通过register加入的
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;
}

看看核心的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
36
37
/**
* subscription : 订阅者
* event : 分发的事件
* isMainThread : 是否在主线程
*/

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case PostThread:
// 直接在本线程中调用订阅函数
invokeSubscriber(subscription, event);
break;
case MainThread:
if (isMainThread) {
// 当前是主线程,那就直接调用订阅函数
invokeSubscriber(subscription, event);
} else {
// 当前是子线程,通过handler实现在主线程中执行
mainThreadPoster.enqueue(subscription, event);
}
break;
case BackgroundThread:
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);
}
}

invokeSubscriber函数利用了反射直接执行一个订阅者的订阅函数。

BackgroundPoster
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
final class BackgroundPoster implements Runnable {
private final PendingPostQueue queue;
...

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);
}
}
}
}

PendingPostQueue是一个PendingPost对象的队列,当enqueue()时就把待发送的事件被封装成了PendingPost对象放到队列中。
BackgroundPoster其实就是一个Runnable对象,当enqueue时,如果这个Runnable对象当前没被执行,就将BackgroundPoster加入EventBus中的一个线程池中,当BackgroundPoster被执行时,会依次取出队列中的事件进行派发。当长时间无事件时BackgroundPoster所属的线程被会销毁,下次再Post事件时再创建新的线程。

HandlerPoster

mainThreadPoster是一个HandlerPoster对象,继承自Handler,构造函数中接收了一个Looper对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
final class HandlerPoster extends Handler {
...
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");
}
}
}
}
...
}

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

AsyncPoster

AsyncPoster就把每个事件都加入线程池中处理

1
2
3
4
5
6
7
8
9
class AsyncPoster implements Runnable {
...
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
queue.enqueue(pendingPost);
eventBus.getExecutorService().execute(this);
}
...
}

一句话总结,post就是把一个Event发出去,EventBus会在它内部存储的方法中,进行扫描,找到参数匹配的,就使用反射进行调用

StickyEvent

EventBus除了提供了post方法,还提供了一个postSticky方法。

1
2
3
4
5
6
7
8
9
10
11
12
/**
* Posts the given event to the event bus and holds on to the event (because it is sticky). The most recent sticky
* event of an event's type is kept in memory for future access. This can be {@link #registerSticky(Object)} or
* {@link #getStickyEvent(Class)}.
*/

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);
}

和post功能类似,但是会把方法存储到stickyEvents中去。
当通过postSticky发送一个事件时,这个类型的事件的最后一次事件会被缓存起来,当有订阅者通过registerSticky注册时,会把之前缓存起来的这个事件直接发送给它。

一些类信息

盗图一张:
class_relation

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

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

注意点

  1. 不支持进程间通信
  2. 同一个onEvent函数不能被注册两次,所以不能在一个类中注册同时还在父类中注册
  3. 默认情况下,当Post一个事件时,这个事件类的父类的事件也会被Post
  4. Post的事件无Subscriber处理时会Post一个NoSubscriberEvent事件

总结

EventBus就是在内部存储了一堆onEvent开头的方法,然后post的时候,根据post传入的参数(Event),去找到匹配的方法,反射调用之。
更简单一点,EventBus就是一个单例内部维持着一个map对象存储了一堆的方法;post无非就是根据参数去查找方法,进行反射调用。