Github: EventBus 分析版本:8a943ef

EventBus3 与之前的相比,其主要差别在于订阅方法可以不再以 onEvent 开头了,改为用注解

介绍

EventBus 是Android上的以发布\订阅事件为核心的库。事件 (event) 通过 post() 发送到总线,然后再分发到匹配事件类型的订阅者 (subscribers) 。订阅者只有在总线中注册 (register) 了才能收到事件,注销 (unrigister) 之后就收不到任何事件了。事件方法必须带有 Subscribe 的注解,必须是 public ,没有返回类型 void 并且只能有一个参数。

EventBus is a central publish/subscribe event system for Android. Events are posted ({@link #post(Object)}) to the bus, which delivers it to subscribers that have a matching handler method for the event type. To receive events, subscribers must register themselves to the bus using {@link #register(Object)}. Once registered, subscribers receive events until {@link #unregister(Object)} is called. Event handling methods must be annotated by {@link Subscribe}, must be public, return nothing (void), and have exactly one parameter (the event).

使用

添加依赖到 Gradle

1
compile 'org.greenrobot:eventbus:3.0.0'

Step1: 定义事件

对事件的定义没有任何要求。

1
2
3
4
5
6
7
public class MessageEvent {
public final String message;

public MessageEvent(String message) {
this.message = message;
}
}

Step2: 准备订阅者

订阅者在定义的时候需要带有 @Subcribe 的注解,EventBus3之后订阅者的方法名可以随意(之前是要以onEvent开头)。

1
2
3
4
5
6
7
8
9
10
11
// This method will be called when a MessageEvent is posted
@Subscribe
public void onMessageEvent(MessageEvent event){
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}

// This method will be called when a SomeOtherEvent is posted
@Subscribe
public void handleSomethingElse(SomeOtherEvent event){
doSomethingWith(event);
}

订阅者同时需要在总线上注册和注销自己。只有当订阅者注册了才能接收到事件。在Android中,通常与 ActivityFragment 的生命周期绑定在一起。

1
2
3
4
5
6
7
8
9
10
11
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}

@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}

Step3: 发送事件

可以从代码的任何地方发送事件,此时注册了的且匹配事件的订阅者能够接收到事件。

1
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));

源码

源码的讲解会按照上文使用的流程分析。

创建EventBus对象

先看看 getDefault() :

1
2
3
4
5
6
7
8
9
10
11
12
static volatile EventBus defaultInstance;

public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}

单例设计模式,用到了double check。再看看 EventBus 的构造方法:

1
2
3
public EventBus() {
this(DEFAULT_BUILDER);
}

什么,既然是单例模式构造函数还 public ??没错,这样的设计是因为不仅仅可以只有一条总线,还可以有其他的线 (bus) ,订阅者可以注册到不同的线上的 EventBus,通过不同的 EventBus 实例来发送数据,不同的 EventBus 是相互隔离开的,订阅者都只会收到注册到该线上事件。

Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a central bus, consider {@link #getDefault()}.

再看看这个 this(DEFAULT_BUILDER) :

1
2
3
EventBus(EventBusBuilder builder) {
//blablabla...
}

这里运用到了builder设计模式,那么来看看这个 Builder 中有哪些参数:

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
public class EventBusBuilder {
//线程池
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
//当调用事件处理函数异常时是否打印异常信息
boolean logSubscriberExceptions = true;
//当没有订阅者订阅该事件时是否打印日志
boolean logNoSubscriberMessages = true;
//当调用事件处理函数异常时是否发送 SubscriberExceptionEvent 事件
boolean sendSubscriberExceptionEvent = true;
//当没有事件处理函数对事件处理时是否发送 NoSubscriberEvent 事件
boolean sendNoSubscriberEvent = true;
//是否要抛出异常,建议debug开启
boolean throwSubscriberException;
//与event有继承关系的是否需要发送
boolean eventInheritance = true;
//是否忽略生成的索引(SubscriberInfoIndex)
boolean ignoreGeneratedIndex;
//是否严格的方法名校验
boolean strictMethodVerification;
//线程池,async 和 background 的事件会用到
ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
//当注册的时候会进行方法名的校验(EventBus3之前方法名必须以onEvent开头),而这个列表是不参加校验的类的列表(EventBus3之后就没用这个参数了)
List<Class<?>> skipMethodVerificationForClasses;
//维护着由EventBus生成的索引(SubscriberInfoIndex)
List<SubscriberInfoIndex> subscriberInfoIndexes;

EventBusBuilder() {
}

//赋值buidler(可用户自定义的)给单例的EventBus,如果单例的EventBus不为null了,则抛出异常
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);
}

}

回到 EventBus 的构造方法中:

1
2
3
4
5
6
7
8
9
10
11
12
13
EventBus(EventBusBuilder builder) {
subscriptionsByEventType = new HashMap<>();//key为event,value为subscriber列表,这个map就是这个事件有多少的订阅者,也就是事件对应的订阅者
typesBySubscriber = new HashMap<>();//key为subscriber,value为event列表,这个map就是这个订阅者有多少的事件,也就是订阅者订阅的事件列表
stickyEvents = new ConcurrentHashMap<>();//粘性事件
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);//MainThread的poster
backgroundPoster = new BackgroundPoster(this);//Backgroud的poster
asyncPoster = new AsyncPoster(this);//Async的poster
//订阅者方法寻找类,默认情况下参数是(null, false, false)
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
//builder中的赋值
//blablabla......
}

首先说一下这三个 HasMapsubscriptionsByEventType 是以 eventkeysubscriber列表value,当发送 event 的时候,都是去这里找对应的订阅者。typesBySubscriber 是以 subscriberkeyevent列表value,当 register()unregister() 的时候都是操作这个map,同时对 subscriptionsByEventType 进行对用操作。stickyEvents 维护的是粘性事件,粘性事件也就是当 event 发送出去之后再注册粘性事件的话,该粘性事件也能收到之前发送出去的 event

Poster

构造函数中同时还创建了 3 个 poster ,这 3 个 poster 负责线程间调度

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
60
61
62
63
64
65
66
67
68
final class HandlerPoster extends Handler {
//队列,即将执行的Post
private final PendingPostQueue queue;
//一个Post最大的在HandleMessage中的时间
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
//handler是否运行起来了
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 pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
//加入到队列中
queue.enqueue(pendingPost);
//如果handleMessage没有运行起来
if (!handlerActive) {
handlerActive = true;
//发送一个空消息,让handleMessage运行起来
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 pendingPost = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
//调用eventBus的方法,分发消息
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;
}
}
}

PendingPost 的数据结构是这样的:

1
2
3
4
5
final class PendingPost {
Object event;//事件
Subscription subscription;//订阅
PendingPost next;//与队列的数据结构有关,指向下一个节点
}

其中 PendingPost 维护着一个可以复用PendingPost对象的复用池,通过 obtainPendingPost(Subscription, Object) 方法复用,通过 releasePendingPost(PendingPost ) 方法回收。

handleMessage() 中有一个死循环,这个死循环不停的从队列中拿数据,然后通过 EventBus.invokeSubscriber() 分发出去。每分发完一次比对一下时间,如果超过了 maxMillisInsideHandleMessage ,那么发送空 message 再次进入到 handlerMessage 中且退出本次循环。这样做的原因是不要阻塞的UI线程??

BackgroundPoster

同理 BackgroundPoster ,只不过 HandlerPoster 是在 handlerMessage 中进行分发操作,而 BackgroundPoster 是在 Runnablerun 方法中将所有队列中的消息取出进行分发,直到取完为止。

AsyncPoster

AsyncPoster 虽然也是在 Runnablerun 方法中取出队列中的消息,但是只取一个。

准备订阅者

关于注解,可以查看一下这篇文章:《Android – Annotation》

了解了注解,那么来看一看 Subscribe 的注解:

1
2
3
4
5
6
7
8
9
10
11
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
//线程模式,订阅者在哪个线程接收到事件
ThreadMode threadMode() default ThreadMode.POSTING;
//是否是粘性事件
boolean sticky() default false;
//优先级,默认为0
int priority() default 0;
}

ThreadMode 是枚举:

1
2
3
4
5
6
public enum ThreadMode {
POSTING,//post的时候是哪个线程订阅者就在哪个线程接收到事件
MAIN,//订阅者在主线程接收到事件
BACKGROUND,//订阅者在主线程接收到消息,如果post的时候不是在主线程的话,那么订阅者会在post的时候那个线程接收到事件。适合密集或者耗时少的事件。
ASYNC//订阅者会在不同的子线程中收到事件。适合操作耗时的事件。
}

全部参数全部上阵的样子:

1
2
3
4
@Subscribe(threadMode = ThreadMode.MAIN, sticky = false, priority = 2)
public void handleSomethingElse(SomeOtherEvent event){
doSomethingWith(event);
}

注册订阅者

1
2
3
4
5
6
7
public void register(Object subscriber) {
//拿到订阅者的class
Class<?> subscriberClass = subscriber.getClass();
//通过class去找到订阅方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
//blablabla...
}

SubscriberMethodFinder

先看看 subscriberMethodFinder.findSubscriberMethods() :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//先从METHOD_CACHE中查看是否已经有这个订阅者了
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
//有了的话直接把订阅者的方法返回
if (subscriberMethods != null) {
return subscriberMethods;
}
//ignoreGeneratedIndex默认是false
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;
}
}

在使用 EventBus.getDefault() 时用的是默认的 builder ,而当使用 EventBusBuilder.installDefaultEventBus() 时是设置自己可配置的 builder 。这里我们先讨论默认情况下的。所以应该走到 findUsingInfo(subscriberClass) 方法来。

1
2
3
4
5
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//1.得到一个FindState对象
FindState findState = prepareFindState();
//blablabla......
}

分别看一下 prepareFindStateFindState :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//FindState复用池大小
private static final int POOL_SIZE = 4;
//FindState复用池
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];

private FindState prepareFindState() {
synchronized (FIND_STATE_POOL) {
//遍历复用池
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
//如果找到可复用state,将该位置清空,返回state
if (state != null) {
FIND_STATE_POOL[i] = null;
return state;
}
}
}
//没找到的话自己new一个
return new FindState();
}

prepareFindState 主要是得到一个FindState,那么看一下 FindState 类的结构:

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
static class FindState {
//订阅者的方法的列表
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
//以EventType为key,method为value
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
//以method的名字生成一个methodKey为key,该method的类(订阅者)为value
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
//构建methodKey的StringBuilder
final StringBuilder methodKeyBuilder = new StringBuilder(128);
//订阅者
Class<?> subscriberClass;
//当前类
Class<?> clazz;
//是否跳过父类
boolean skipSuperClasses;
//SubscriberInfo
SubscriberInfo subscriberInfo;

void initForSubscriber(Class<?> subscriberClass) {
//clazz为当前类
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
//blablabla......
}

继续 findUsingInfo(subscriberClass) 的流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//1.得到一个FindState对象
FindState findState = prepareFindState();
//2.subscriberClass赋值给findState
findState.initForSubscriber(subscriberClass);
//2.findState的当前class不为null
while (findState.clazz != null) {
//2.默认情况下,getSubscriberInfo()返回的是null
findState.subscriberInfo = getSubscriberInfo(findState);
//2.那么这个if判断就跳过了
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 {//2.来到了这里
findUsingReflectionInSingleClass(findState);
}
//blablabla......
}
//blablabla......
}

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
43
44
45
46
47
48
//在较新的类文件,编译器可能会添加方法。那些被称为BRIDGE或SYNTHETIC方法。EventBus必须忽略两者。有修饰符没有公开,但在Java类文件中有格式定义
private static final int BRIDGE = 0x40;
private static final int SYNTHETIC = 0x1000;
//需要忽略的修饰符
private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;

private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
//通过反射,获取到订阅者的所有方法
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
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,是否有需要忽略修饰符
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
//获得方法的参数
Class<?>[] parameterTypes = method.getParameterTypes();
//EventBus只允许订阅方法后面的订阅事件是一个
if (parameterTypes.length == 1) {
//判断该方法是不是被Subcribe的注解修饰着的
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
//确定这是一个订阅方法
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
//通过Annotation去拿一些数据
ThreadMode threadMode = subscribeAnnotation.threadMode();
//添加到subscriberMethods中
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, ubscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
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)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName + " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}

关于 BRIDGESYNTHETIC ,注释写道:

In newer class files, compilers may add methods. Those are called bridge or synthetic methods. EventBus must ignore both. There modifiers are not public but defined in the Java class file format: http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6-200-A.1

在较新的类文件,编译器可能会添加方法。那些被称为 BRIDGE 或 SYNTHETIC 方法。EventBus 必须忽略两者。有修饰符没有公开,但在 Java 类文件中有格式定义。

该方法流程是:

  1. 拿到当前 class 的所有方法
  2. 过滤掉不是 public 和是 abstract、static、bridge、synthetic 的方法
  3. 过滤出方法参数只有一个的方法
  4. 过滤出被Subscribe注解修饰的方法
  5. 将 method 方法和 event 事件添加到 findState
  6. 将 EventBus 关心的 method 方法、event 事件、threadMode、priority、sticky 封装成 SubscriberMethod 对象添加到 findState.subscriberMethods 列表中

那么,先来看看 findState.checkAdd() :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
// 此时的情况是已经在缓存中有这个method和eventType的,发生情况是子类和父类都是相同事件,相同方法名,切超过3层继承关系
throw new IllegalStateException();
}
// Put any non-Method object to "consume" the existing Method
anyMethodByEventType.put(eventType, this);
}
return checkAddWithMethodSignature(method, eventType);
}
}

checkAdd 分为两个层级的 check ,第一层级只判断 event type,这样速度快一些;第二层级是多方面判断。anyMethodByEventType 是一个 HashMap ,HashMap.put() 方法返回的是之前的 value ,如果之前没有 value 的话返回的是 null ,通常一个订阅者(包括继承关系)不会有多个相同方法接收同一事件,但是可能会出现子类订阅这个事件的同时父类也订阅了此事件的情况,那么 checkAddWithMenthodSignature() 就排上了用场:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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();
//存储到以methodKey为Key,method的类为value的map中,返回之前methodKey存储的值
Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
//如果这个值不存在或者这个值是method的类的父类的话,返回true
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;
}
}

这里的稍微逻辑有一些乱,但是其主要思想就是不要出现一个订阅者(主要是有继承关系的订阅者)有多个相同方法订阅的是同一事件。

现在回过头来看一下 SubscriberMethod 这个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class SubscriberMethod {
final Method method;
final ThreadMode threadMode;
final Class<?> eventType;
final int priority;
final boolean sticky;
/** Used for efficient comparison */
String methodString;

public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
this.method = method;
this.threadMode = threadMode;
this.eventType = eventType;
this.priority = priority;
this.sticky = sticky;
}
//blablabla......
}

SubscriberMethod 类将EventBus所需要的全封装起来了。

再回到 findUsingInfo(subscriberClass) :

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 List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//1.得到一个FindState对象
FindState findState = prepareFindState();
//2.subscriberClass赋值给findState
findState.initForSubscriber(subscriberClass);
//2.findState的当前clazz不为null
while (findState.clazz != null) {
//2.默认情况下,getSubscriberInfo()返回的是null
findState.subscriberInfo = getSubscriberInfo(findState);
//2.那么这个if判断就跳过了
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 {//2.来到了这里
findUsingReflectionInSingleClass(findState);
}
//3.将当前clazz变为该类的父类,然后再进行while循环的判断
findState.moveToSuperclass();.
}
//3.将findState释放资源,放回复用池中,返回封装好的SubscriberMethod列表
return getMethodsAndRelease(findState);
}

总结一下 subscriberClass 的流程:

  1. 从复用池中或者 new 一个,得到 findState

  2. 将 subscriberClass 复制给 findState

    1. 进入循环,判断当前 clazz 为不为null

    2. 不为 null 的话调用 findUsingReflectionInSingleClass() 方法得到该类的所有的 SubscriberMethod

    3. 将 clazz 变为 clazz 的父类,再次进行循环的判断

  3. 返回所有的 SubscriberMethod

现在一层层 return 返回到了 findSubscriberMethods() 方法中,将所有的 SubscriberMethod 存储到 METHOD_CACHE 当中。

1
METHOD_CACHE.put(subscriberClass, subscriberMethods);

再一层层的 return 返回到 EventBus.register() 中:

1
2
3
4
5
6
7
8
9
10
11
12
13
public void register(Object subscriber) {
//拿到订阅者的class
Class<?> subscriberClass = subscriber.getClass();
//通过class去找到订阅方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
//遍历
for (SubscriberMethod subscriberMethod : subscriberMethods) {
//订阅
subscribe(subscriber, subscriberMethod);
}
}
}

EventBus.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
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//拿到事件
Class<?> eventType = subscriberMethod.eventType;
//封装一个Subscription出来,Subscription是将订阅者和订阅方法封装类(包括threadMode、sticky等)封装一起来了
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//subscriptionsByEventType是以eventType为key,Subscription的ArrayList为value的HashMap,事件订阅者的保存队列,找到该事件所订阅的订阅者以及订阅者的方法、参数等
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
//如果没有数据,说明此事件是还没有注册过的
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {//说明此事件是已经有地方注册过了的
if (subscriptions.contains(newSubscription)) {//说明该订阅者已经注册过了的
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType);
}
}

int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
//根据优先级添加到指定位置
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
//typesBySubscriber以subscriber为key,eventType的ArrayList为value的HashMap,订阅者订阅的事件列表,找到改订阅者所订阅的所有事件
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
//添加到该订阅者的所以订阅方法列表中
subscribedEvents.add(eventType);
//如果是粘性事件
if (subscriberMethod.sticky) {
//是否支持继承关系,就是记录事件的父类(比如事件是ArrayList类型的,那么如果eventInheritance为true的话,会去找为List类型的事件。)
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>).
//stickyEvents以eventType为key,event为value的ConcurrentHashMap,Sticky事件保存队列
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 的 value 的 List 中,而 subscriptionsByEventType 是事件订阅者的保存队列,找到该事件所订阅的订阅者以及订阅者的方法、参数等,然后再添加到 typesBySubscriber 的 value 的 List 中,而 typesBySubscriber 是订阅者订阅的事件列表,找到改订阅者所订阅的所有事件,最后判断一下是否是粘性事件,是的话判断事件是否需要考虑继承关系,再分发这个黏性事件。

那么来看一下 checkPostStickyEventToSubscription 这个方法:

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 这个方法:

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 postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING://当前线程直接调用
invokeSubscriber(subscription, event);
break;
case MAIN:
if (isMainThread) {//如果现在是UI线程,直接调用
invokeSubscriber(subscription, event);
} else {//否则加入到mainThreadPoster队列中
mainThreadPoster.enqueue(subscription, event);
}
break;
case BACKGROUND:
if (isMainThread) {//如果现在是UI线程,加入到backgroundPoster队列中
backgroundPoster.enqueue(subscription, event);
} else {//否则直接调用
invokeSubscriber(subscription, event);
}
break;
case ASYNC://无论如何都加入到asyncPoster队列中
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}

这三个 Poster 在上文都已经分析过了,那么来看看 invokeSubscriber 方法吧:

1
2
3
4
5
6
7
8
9
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);
}
}

最终通过反射调用。

注销订阅者

讲完了注册订阅者,再来看看注销订阅者吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
public synchronized void unregister(Object subscriber) {
//typesBySubscriber以subscriber为key,eventType的ArrayList为value的HashMap,订阅者订阅的事件列表,找到改订阅者所订阅的所有事件
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
//remove掉
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}

再看看 unsubscribeByEventType :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
//subscriptionsByEventType是以eventType为key,Subscription的ArrayList为value的HashMap,事件订阅者的保存队列,找到该事件所订阅的订阅者以及订阅者的方法、参数等
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;
//remove掉
subscriptions.remove(i);
i--;
size--;
}
}
}
}

注销的流程就是将 typesBySubscribersubscriptionsByEventType 中的关于该订阅者以及该订阅者中的方法、事件等 remove 掉。

发送事件

看完注册和注销之后,再来看看发送事件。可以从代码的任何地方发送事件,此时注册了的且匹配事件的订阅者能够接收到事件。通过 EventBus.post(event) 来发送事件。

1
2
3
4
5
public void post(Object event) {
//1.得到PostingThreadState
PostingThreadState postingState = currentPostingThreadState.get();
//blablabla......
}

currentPostingThreadState 是一个 ThreadLocal 对象,而 ThreadLocal 是线程独有,不会与其他线程共享的。

1
2
3
4
5
6
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};

其实现是返回一个 PostingThreadState 对象,而 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;
}

PostingThreadState 封装的是当前线程的 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
28
29
public void post(Object event) {
//1.得到PostingThreadState
PostingThreadState postingState = currentPostingThreadState.get();
//2.获取其中的队列
List<Object> eventQueue = postingState.eventQueue;
//2.将该事件添加到队列中
eventQueue.add(event);
//2.如果postingState没有进行发送
if (!postingState.isPosting) {
//2. 判断当前线程是否是主线程
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
//2.将isPosting状态改为true,表明正在发送中
postingState.isPosting = true;
//2.如果取消掉了,抛出异常
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
//2.循环,直至队列为空
while (!eventQueue.isEmpty()) {
//2.发送事件
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}

最后走到一个 while 循环,判断事件队列是否为空了,如果不为空,继续循环,进行 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
27
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {//是否查看事件的继承关系
//找到事件的所以继承关系的事件类型
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) {
//发送一个NoSubscriberEvent的事件出去
post(new NoSubscriberEvent(this, event));
}
}
}

lookupAllEventTypes() 就是查找该事件的所有父类,返回所有的该事件的父类的 class 。它通过循环和递归一起用,将一个类的父类(接口)全部添加到全局静态变量 eventTypes 集合中。再看一下 postSingleEventForEventType 方法:

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) {
//所有订阅了event的事件集合
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
//这里调用的postToSubscription方法,上面有解析
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;
}

至此,EventBus 的解析就结束了。

EventBus流程整理

订阅

  1. 根据订阅者来找到订阅方法和事件,封装成 SubscriberMehod
  2. 循环每个 SubscriberMethod
  3. 通过事件得到该事件的所有订阅者列表,再根据优先级插入到 subscriptionsByEventType 的所有订阅者列表中
  4. 通过订阅者得到该订阅者的所有事件列表,再将事件添加到 typeBySubscriber 的所以事件列表中
  5. 是否是粘性事件
  6. 是的话进行分发,post此事件给当前订阅者,不是的话不管
  7. 结束本次循环,跳到 2

发送

  1. currentPostingThreadState 中得到当前线程的 PostThreadState 信息
  2. 将此事件添加到 PostPostThreadState 的事件队列中
  3. 判断是否再分发
  4. 不是的话,循环队列,是的话跳 7
  5. 判断是个需要继承关系
  6. 是的话,循环得到父类,不是的话跳 7
  7. 查找该事件的订阅者,循环订阅者
  8. 根据 ThreadMoth 发送事件
  9. 结束本次循环订阅者,跳 7
  10. 结束本次循环队列,跳 4

参考