前言
在上一篇文章:EventBus 3.0初探: 入门使用及其使用 完全解析中,笔者为大家介绍了EventBus 3.0的用法,相信大家对其的使用也比较熟悉了。我们学习使用一个开源库,不但要知道其怎么使用,也要对其的实现原理有一定的熟悉,学习并借鉴它优秀的实现思想,这样对我们以后的开发又或者是自己的开源项目都有很大的意义。那么今天的文章,就是EventBus 3.0的进阶,剖析它的实现原理以及对其使用的设计模式进行解析。
本文导读
由于EventBus较为复杂,因此本文也相当长,所以本文分为以下几个部分:创建、注册、发送事件、关于粘性事件的解析、以及最后的思考。读者可以有选择性地选取某部分来进行阅读。
实现原理
创建
上一篇文章提到,要想注册成为订阅者,必须在一个类中调用如下:
EventBus.getDefault().register(this);
那么,我们看一下getDefault()的源码是怎样的,EventBus#getDefault():
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
可以看出,这里使用了单例模式,而且是双重校验的单例,确保在不同线程中也只存在一个EvenBus的实例。
单例模式:一个类有且仅有一个实例,并且自行实例化向整个系统提供。
然而,我们看看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()}.
*/
public EventBus() {
this(DEFAULT_BUILDER);
}
它的构造方法并没有设置成私有的!这是为什么?从注解我们看到,每一个EventBus都是独立地、处理它们自己的事件,因此可以存在多个EventBus,而通过getDefault()方法获取的实例,则是它已经帮我们构建好的EventBus,是单例,无论在什么时候通过这个方法获取的实例都是同一个实例。除此之外,我们可以通过建造者帮我们建造具有不同功能的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);
//一系列的builder赋值
}
可以看出,对成员变量进行了一系列的初始化,那么我们来看看几个关键的成员变量:
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
private final Map<Object, List<Class<?>>> typesBySubscriber;
private final Map<Class<?>, Object> stickyEvents;
subscriptionsByEventType:以event(即事件类)为key,以订阅列表(Subscription)为value,事件发送之后,在这里寻找订阅者,而Subscription又是一个CopyOnWriteArrayList,这是一个线程安全的容器。你们看会好奇,Subscription到底是什么,其实看下去就会了解的,现在先提前说下:Subscription是一个封装类,封装了订阅者、订阅方法这两个类。
typesBySubscriber:以订阅者类为key,以event事件类为value,在进行register或unregister操作的时候,会操作这个map。
stickyEvents:保存的是粘性事件,粘性事件上一篇文章有详细描述。
回到EventBus的构造方法,接下来实例化了三个Poster,分别是mainThreadPoster、backgroundPoster、asyncPoster等,这三个Poster是用来处理粘性事件的,我们下面会展开讲述。接着,就是对builder的一系列赋值了,这里使用了建造者模式。
建造者模式:将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示。
这里的建造者是EventBusBuilder,它的一系列方法用于配置EventBus的属性,使用getDefault()方法获取的实例,会有着默认的配置,上面说过,EventBus的构造方法是公有的,所以我们可以通过给EventBusBuilder设置不同的属性,进而获取有着不同功能的EventBus。那么我们来列举几个常用的属性加以讲解:
//默认地,EventBus会考虑事件的超类,即事件如果继承自超类,那么该超类也会作为事件发送给订阅者。
//如果设置为false,则EventBus只会考虑事件类本身。
boolean eventInheritance = true;
public EventBusBuilder eventInheritance(boolean eventInheritance) {
this.eventInheritance = eventInheritance;
return this;
}
//当订阅方法是以onEvent开头的时候,可以调用该方法来跳过方法名字的验证,订阅这类会保存在List中
List<Class<?>> skipMethodVerificationForClasses;
public EventBusBuilder skipMethodVerificationFor(Class<?> clazz) {
if (skipMethodVerificationForClasses == null) {
skipMethodVerificationForClasses = new ArrayList<>();
}
skipMethodVerificationForClasses.add(clazz);
return this;
}
//更多的属性配置请参考源码,均有注释
//...
那么,我们通过建造者模式来手动创建一个EventBus,而不是使用getDefault()方法:
EventBus eventBus = EventBus.builder()
.eventInheritance(false)
.sendNoSubscriberEvent(true)
.skipMethodVerificationFor(MainActivity.class)
.build();
注册
好了,以上说了一大推关于EventBus的创建,接下来,我们继续讲它的注册过程。要想使一个类成为订阅者,那么这个类必须有一个订阅方法,以@Subscribe注解标记的方法,接着调用register()方法来进行注册。那么我们直接来看EventBus#register()。
register
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
先获取了订阅者类的class,接着交给SubscriberMethodFinder.findSubscriberMethods()处理,返回结果保存在List中,由此可推测通过上面的方法把订阅方法找出来了,并保存在集合中,那么我们直接看这个方法,SubscriberMethodFinder#findSubscriberMethods()。
findSubscriberMethods
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//首先从缓存中取出subscriberMethodss,如果有则直接返回该已取得的方法
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
//从EventBusBuilder可知,ignoreGenerateIndex一般为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 {
//将获取的subscriberMeyhods放入缓存中
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
从上面的逻辑可以知道,一般会调用findUsingInfo方法,我们接着看SubscriberMethodFinder#findUsingInfo方法:
findUsingInfo
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//准备一个FindState,该FindState保存了订阅者类的信息
FindState findState = prepareFindState();
//对FindState初始化
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//获得订阅者的信息,一开始会返回null
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {