EventBus源代码解析:1、初始化与订阅者注册

和以前一样,我们同样从我们最经常使用的代码入手,分析EventBus到底是如何进行工作的。所以,第一步,我们先分析EventBus的初始化代码,看看初始化代码当中,都做了哪些工作?

一:初始化

单例模式

1
2
3
4
5
6
7
8
9
10
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}

首先,我们最经常使用的EventBus的默认配置,其实就是一个我们常用的单例模式:

  • 首先尝试获取defaultInstance,如果defaultInstance为null,说明默认的EventBus还没有初始化,因此接下来的工作就是需要对EventBus进行初始化。
  • 此时,为了同一个时刻只有一个EventBus在初始化,也是为了避免多个线程同时访问的时候,各自生成了不同的EventBus对象,因此我们需要对初始化的代码块进行同步。当然同步的范围选择很重要,同步的范围必须是所有的线程都能够同时看到,因此选用了EventBus的类对象作为同步代码块的同步对象。
  • 此时,由于进入到同步代码块之后,可能是由于和其他线程竞争,但没有竞争过,那么此时的时候,很有可能其他线程当中已经将EventBus初始化完成了,所以此时需要再次检查EventBus有没有初始化好,没有的话,说明是第一次进行初始化,那进行初始化工作就可以。
  • 返回唯一的EventBus对象defaultInstance。

具体的初始化工作

构造函数:

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

构造函数非常简单,调用了另外的构造函数EventBus(EventBusBuilder builder)实现功能,我们还是需要看看这个构造函数中,都做了哪些工作?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
EventBus(EventBusBuilder builder) {
// 订阅者们,根据Event类型分类:Key是订阅者的类,Value为对应的订阅者
subscriptionsByEventType = new HashMap<Class<?>, CopyOnWriteArrayList<Subscription>>();
// 订阅者所支持的Event类型
typesBySubscriber = new HashMap<Object, List<Class<?>>>();
// 保存Sticky Events,注意,这个地方用的是一个线程安全的HashMap
stickyEvents = new ConcurrentHashMap<Class<?>, Object>();
// 主线程的Poster
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
// 后台线程的Poster
backgroundPoster = new BackgroundPoster(this);
// 异步的Poster
asyncPoster = new AsyncPoster(this);
// 订阅者方法寻找器
subscriberMethodFinder = new SubscriberMethodFinder(builder.skipMethodVerificationForClasses);
logSubscriberExceptions = builder.logSubscriberExceptions;
logNoSubscriberMessages = builder.logNoSubscriberMessages;
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
throwSubscriberException = builder.throwSubscriberException;
eventInheritance = builder.eventInheritance;
executorService = builder.executorService;
}
  • 初始化了以下的队列
    • subscriptionsByEventType:Event的类型作为Key的HashMap,需要注意的是,其中用到了一个CopyOnWriteArrayList,当列表中的元素,其读取次数远远超过写入次数的时候,使用该集合类可以大大提高效率,且该类是线程同步保护的。
    • typesBySubscriber:同样的一个HashMap,保存了某一个订阅者当中所支持的消息类型。有个细节可以注意到,这个地方HashMap的Key是List<Class<?>>,而subscriptionsByEvent中的Key是指定了OnWriteArrayList>,这其中有什么技巧吗?我的理解是这个样子的:
      • 从调用的次数上来考虑,当我们POST一个event的时候,按照我们的常规思路,EventBus就应该根据Event的类型,也就是类去找到那些能够处理这个Event的Subcription,那么这些Subcriptions保存在哪里呢?–>CopyOnWriteArrayList。所以对于这一个列表来说,我们很少回去改动其中的元素,除非有新的Subcription注册。但另外一个,还没想到做什么使用,可能是注销的时候依次注销所注册的订阅者?
    • stickyEvents:保存stickey的Events,需要注意的是,这里面用到的都是ConcurrentHashMap,是线程安全的。
  • 初始化了以下的Poster(后面会依次分析几种Poster的不同实现)
    • mainThreadPoster:通过运行在main线程上的Handler实现
    • backgroundPoster:本质上为一个Runnable
    • asyncPoster:本质上同样为一个Runnable
  • 注册了一个subscriberMethodFinder:即查找订阅者类当中对应的Handler方法
  • 初始化了各种参数:需要注意的是,其中有一个executorService,其默认实现为

    private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();

    后面我们还看到,很多消息的Post都是通过该线程池实现。

上面,我们分析完成EventBus的初始化工作,下面我们继续来分析一下我们在代码中向EventBus注册订阅者的时候,都发生了什么事情?

二、订阅者注册

1、注册:

我们一般情况下,使用的注册代码是:

1
register(Object subscriber)

跟踪代码,发现该代码实际上通过调用resiter(Object subscriber, boolean sticky, int priority)实现,我们来看看这段代码都做了哪些工作?

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

上面的代码主要做了两件事情:

  1. 从对应的subscriber类中查找到所有的SubscriberMethod
  2. 依次订阅所有的SubscriberMethod

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
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
100
101
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
// 获取类的全名作为key
String key = subscriberClass.getName();
// 订阅者方法列表
List<SubscriberMethod> subscriberMethods;
// 尝试从methodCache中获取订阅者方法
synchronized (methodCache) {
subscriberMethods = methodCache.get(key);
}
// 如果订阅者方法列表已经存在,则直接返回
if (subscriberMethods != null) {
return subscriberMethods;
}

subscriberMethods = new ArrayList<SubscriberMethod>();
Class<?> clazz = subscriberClass;
HashSet<String> eventTypesFound = new HashSet<String>();
StringBuilder methodKeyBuilder = new StringBuilder();
while (clazz != null) {
String name = clazz.getName();
// 如果这些类是java,javax或者android的话,则直接跳过。
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)
// 从EventBus2.2开始,强制必须将修饰符设置为public
Method\[\] methods = clazz.getDeclaredMethods();
// 依次遍历类的全部方法
for (Method method : methods) {
// 获取方法名
String methodName = method.getName();
// 判断方法名是否以ON\_EVENT\_METHOD_NAME,即是否以"onEvent"开头
if (methodName.startsWith(ON\_EVENT\_METHOD_NAME)) {
// 获取方法的修饰符
int modifiers = method.getModifiers();
// 要求方法匹配public修饰符,并且不是(Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC)中任一种
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
// 获取参数的类型
Class<?>\[\] parameterTypes = method.getParameterTypes();
// 如果参数的类型只有一种,也就是说,参数只有一个
if (parameterTypes.length == 1) {
// 获取方法名当中去掉onEvent剩下的部分,并根据这一部分判断其工作在哪个县城之上
String modifierString = methodName.substring(ON\_EVENT\_METHOD_NAME.length());
ThreadMode threadMode;
if (modifierString.length() == 0) {
// PostThread
threadMode = ThreadMode.PostThread;
} else if (modifierString.equals("MainThread")) {
// MainThread
threadMode = ThreadMode.MainThread;
} else if (modifierString.equals("BackgroundThread")) {
// BackgroundThread
threadMode = ThreadMode.BackgroundThread;
} else if (modifierString.equals("Async")) {
// AsyncThread
threadMode = ThreadMode.Async;
} else {
if (skipMethodVerificationForClasses.containsKey(clazz)) {
continue;
} else {
throw new EventBusException("Illegal onEvent method, check for typos: " + method);
}
}
// 获取订阅者处理方法onEvent方法的参数类型
Class<?> eventType = parameterTypes\[0\];
methodKeyBuilder.setLength(0);
// 添加方法名
methodKeyBuilder.append(methodName);
// 添加方法类型
methodKeyBuilder.append('>').append(eventType.getName());
String methodKey = methodKeyBuilder.toString();
// 将methodKey添加到eventTypesFound当中 true:说明该方法没有被添加过,false:说明该方法已经被添加过
if (eventTypesFound.add(methodKey)) {
// Only add if not already found in a sub class
// 如果methodKey在子类当中没有被添加过,则构造SubscriberMethod,并添加到subscriberMethods当中
subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));
}
}
} else if (!skipMethodVerificationForClasses.containsKey(clazz)) {
Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + clazz + "."
\+ methodName);
}
}
}
// 该类处理完成,继续处理其父类!!!
clazz = clazz.getSuperclass();
}
// 如果该类或者其父类当中不包含订阅者方法,那么则抛出异常
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called "
\+ ON\_EVENT\_METHOD_NAME);
} else {
// 该类或者其父类当中,包含订阅者方法,则将其添加到methodCache当中
synchronized (methodCache) {
methodCache.put(key, subscriberMethods);
}
return subscriberMethods;
}
}

SubscriberMethod方法的程序流程图: findSubscriberMethods 简单的理解, findSubscriberMethods的工作就依次遍历指定类中的所有方法,从中找到EventBus的handler并将其添加到subscriberMethods集合当中。具体的步骤如下:

  1. 首先判断clazz类以否是java/javax/android的类,如果是,则说明这个类并不是我们的订阅者(可能是订阅者的父类,不需要处理)。
  2. 然后遍历类中所有的方法,首先挑选出其中以onEvent开头的方法,继续判断是否是我们的Event处理方法。
  3. 判断该方法的修饰符,要求方法匹配public修饰符,并且不是(Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC)中任一种。
  4. 获取onEvent方法的参数类型,即要处理的Event的类型。
  5. 构建SubscriberMethod对象,并添加到subscriberMethods
  6. 获取clazz的父类,重复步骤1-6

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
// Must be called in synchronized block
// 必须要在同步快中执行
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {

// 获取订阅者处理方法的参数类型,即Event事件的类型
Class<?> eventType = subscriberMethod.eventType;
// 根据类型尝试从subscriptionsByEventType中获取参数类型,即Event事件类型所对应的订阅者列表。
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
// 生成新的订阅者对象
Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);
// 如果订阅者列表为null,则说明是头一次添加该Event类型。
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);
// 从EventBus2.2之后,设置方法必须为public
// 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;
}
}

// 保存订阅者类所能够处理的EventType
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<Class<?>>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);

// 如果Event设置为sticky
if (sticky) {
Object stickyEvent;
synchronized (stickyEvents) {
stickyEvent = stickyEvents.get(eventType);
}
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());
}
}
}

其程序架构图如下: subscribe 这个其实理解起来比较简单,主要分了下面几个步骤:

  1. 根据订阅者所在的类,订阅者的方法,生成相应的订阅者对象,即Subscription对象。
  2. 获取Event的事件类型,查看此事件是否有相应的List,如果有,则说明之前有注册过其他的可以处理该事件类型的Subcription,那么则根据优先级将此次的Subcription对象插入到合适的位置,否则则新建List,并将Subcription对象插入进来。