您的位置:首页 > 其它

EventBus源码解析(二)-EventBus实例化

2017-12-27 16:03 225 查看

一、默认EventBus实例

当某个类需要订阅事件时,我们通常会先在这个类的某处(如初始化方法)添加如下代码以完成EventBus的注册。

EventBus.getDefault().register(this);


然后在适当的地方添加如下代码以完成EventBus的注册解除,防止泄露。

EventBus.getDefault().unregister(this);


无论是注册或者解除注册,无一例外,都是通过EventBus.getDefault()获取到的EventBus实例来完成的。那么getDefault()方法做了什么操作呢?我们跟进代码看看。

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


getDefault()方法其实很简单,就是使用单例模式,获取到了唯一的EventBus对象。初次使用时,instance对象势必为null,此时就会通过EventBus的无参构造函数创建出一个EventBus实例对象。无参构造函数的实现如下:

public EventBus() {
this(DEFAULT_BUILDER);
}


可以看到,EventBus的无参构造函数,最终调用的还是带有单个参数的构造函数,其参数类型是EventBusBuilder,望文生义,EventBusBuilder明显是采用建造者模式实现的,这部分我们后面再分析。无参构造函数调用了有参构造函数,并传入了DEFAULT_BUILDER实参。那么,DEFAULT_BUILDER又是怎样的呢?其实它就是一个EventBusBuilder对象,只有预设定的默认配置。

private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();


DEFAULT_BUILDER传入到有参的EventBus构造函数后,会执行一些初始化的工作,如下:

EventBus(EventBusBuilder builder) {
logger = builder.getLogger();
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadSupport = builder.getMainThreadSupport();
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
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;
}


在这里,会取出EventBusBuilder的各项配置值,赋值给相应的EventBus中的成员。这是很典型的建造者模式,一般当有多项配置时,我们会考虑采用这种模式。

经历以上流程之后,默认的EventBus实例就通过getDefault方法获取到了,并且这个EventBus是全局唯一的。

代码分析到这里,我们大概可以知道了,EventBus实例化可以有两种方式:

- 使用默认的配置,即getDefault()方式

- 使用EventBusBuilder自定义配置,之后通过build生成

二、默认配置

EventBusBuilder是EventBus的建造者,负责初始化EventBus的各项配置,并生成EventBus对象。通过第一节的分析,我们会有一个疑问:EventBus的默认配置到底是怎么样的呢?这个问题其实可以换个问法:EventBusBuilder的默认配置到底是怎么样的呢?让我们赶紧追进代码分析吧。

public class EventBusBuilder {
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;
Logger logger;
MainThreadSupport mainThreadSupport;

...
}


分析以上EventBusBuilder的成员及赋值,可以得出如下信息:

logSubscriberExceptions :是否打印订阅者异常信息,默认开启
logNoSubscriberMessages :某个事件没有订阅者时,是否打印信息,默认开启
sendSubscriberExceptionEvent :出现订阅者异常时,是否发送异常事件,默认开启
sendNoSubscriberEvent :某个事件没有订阅者时,是否发送无订阅者的事件,默认开启
throwSubscriberException :是否抛出订阅者异常信息,默认关闭
eventInheritance :事件是否可以继承形式订阅,默认开启
ignoreGeneratedIndex :忽略索引生成,默认关闭
strictMethodVerification :是否开启方法严格验证,默认关闭
executorService :线程池,默认是newCachedThreadPool,即没有核心线程、但最大线程数是Integer.MAX_VALUE的线程池
skipMethodVerificationForClasses :跳过为订阅者类里面的方法进行校验,校验包括注解信息、修饰符是否是public且非static\final的,默认为空
subscriberInfoIndexes :订阅者信息索引,由注解处理器生成
mainThreadSupport :专为Android的主线程定制,持有主线程looper引用


结合第一节的分析,到这里我们可以得出结论,EventBus的默认配置是:

- 当出现订阅者异常时,打印异常log

- 当事件没有订阅者时,打印没有订阅者log

- 当出现订阅者异常时,发送异常事件

- 当事件没有订阅者时,发送无订阅者事件

- 捕获异常信息,防止崩溃

- 事件可以继承

- 编译时生成索引

- 采用最大限制是Integer.MAX_VALUE的缓存线程池

- 为每个订阅者类都进行方法校验

- 当处于Android平台时,确保可以切换到主线程

三、自定义配置

那么如何进行自定义的EventBus配置呢?聪明的你一定想到了。是的,我们可以通过EventBusBuilder来实现自定义配置。EventBusBuilder内部提供了一系列的配置方法,方便用户采用链式调用的方式,来生成一个EventBusBuilder对象。然而,通过查看EventBus源码可知,EventBusBuilder的构造方法的修饰符是protected的,也就是说,用户无法通过直接new的方式来创建EventBusBuilder对象。这样不就无法自定义配置了吗?别急,虽然我们无法直接new出一个EventBusBuilder对象,但是EventBus类提供了一个静态方法builder(),该方法内部默认new了一个EventBusBuilder对象,如下:

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


通过builder()方法,用户就可以获取到EventBusBuilder对象,之后就可以随心所欲地自定义配置了。配置有如下两种使用姿势:

姿势1:
EventBus.builder().logNoSubscriberMessages(false)
.logSubscriberExceptions(false).eventInheritance(false)...
.installDefaultEventBus();


姿势2:
EventBus.builder().logNoSubscriberMessages(false)
.logSubscriberExceptions(false).eventInheritance(false)...
.build();


上述两种姿势看起来非常相似,但其实是有区别的,区别就在于创建EventBus实例的方式,姿势1使用的是installDefaultEventBus方法,姿势2使用的是build方法。我们来看看这两种方法的内部实现。

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


看出区别了吗?installDefaultEventBus方法在内部其实也是调用的build方法,但不同的是,installDefaultEventBus可以确保EventBus实例的全局唯一性,当defaultInstance非空时,会直接抛出异常。而姿势2直接使用build方法创建EventBus实例的方式,则需要用户自身确保EventBus实例的全局唯一性。

EventBus并非一定要全局唯一,但确保全局唯一,不是可以更好更合理地管理和分发事件吗?

四、结束语

通过以上几小节的分析,我们已经知道了EventBus的默认配置情况,以及如何自定义配置。但如果再仔细观察,会发现,在 EventBus(EventBusBuilder builder) 构造函数中,还默认实例化了几个成员对象:

subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();

mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);

subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);


这些成员是用来做什么的呢?我们先留个悬念,在后面的几章中进行详细的分析。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: