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

一、默认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);

这些成员是用来做什么的呢?我们先留个悬念,在后面的几章中进行详细的分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值