Android实践: 图解EventBus架构

EventBus架构图解.png

这篇文章主要分析EventBus的基本框架, 不涉及具体的代码细节.

我们可以把EventBus分成3个模块, 注册(register), 发送事件(post)和执行方法(invoke).

注册

图解中的上部分为注册流程.
首先, 每个订阅类都会包含订阅信息, 就是用@Subscribe注释的方法, 每当调用EventBus#register方法时, EventBus就会收集相关信息, 每一个@Subscribe注释的方法都可以转化成一个订阅信息Subscription, 如图解, 这个Subscription包含了执行方法需要用到的基本信息.

收集到的信息会分别存放在typesBySubscribersubscriptionsByEventType两个Map中, 后续就是根据这两个Map中的信息来获取订阅信息列表, 接着根据订阅信息来处理发送的事件和执行方法.

特殊地, 如果注册的方法中有接收sticky事件, 那么就会直接发送一次已有的sticky事件

发送事件

图解中间部分为发送事件的处理流程.
当调用EventBus#post方法时, 根据传进来的事件Object, 根据它的Class可以获取到订阅了这种Class的订阅信息(Subscription)列表, 如果允许继承关系(eventInheritance), 还会获取它的祖先类对应的订阅信息列表. 当然这种继承关系会缓存起来, 放到eventTypesCache中, 方便复用.

最后, 根据post进来的事件实例, 就会得到一些订阅信息, 每个订阅信息代表一个方法要被执行, 然后就是根据订阅信息来执行方法了.

执行方法

图解的下部分为执行方法的流程.

首先Subscription和事件Object会被封装到一起, 方便处理, 这时, 我们就知道, 应该在什么线程执行哪个订阅者Object的哪个方法, 传参是哪个事件Object了.

然后根据注释中的ThreadMode参数选择合适的线程. 然后把封装好的PendingPost放入对应的队列中, 等待执行. 下面简单说下线程处理的实现.

Posting

会直接在当前线程执行

Main

会在主线程执行, 具体就是通过一个Handler来循环从队列中取PendingPost, 然后执行方法.

Background

会在后台线程执行, 具体是从线程池中取出一条线程, 然后在这条线程中按顺序逐个取出PendingPost处理, 所以如果某个方法是耗时的, 就会阻塞其他方法.

Async

也会在后台线程执行, 和Background的区别在于, 每一个PendingPost都会从线程池中取一条线程来执行, 所以相互之间不会阻塞.

总结

以上就是EventBus的基本结构, 虽然源码看似很复杂, 实际上实现的原理并不复杂, 如果有兴趣, 建议从开始的版本开始阅读, 因为那时的代码只有结构, 从这个角度也能看出EventBus的强大之处, 经过那么久, 代码结构仍然没有大的变化.
当然除了结构, 其中还有一些细节值得我们好好学习揣摩.

  1. 使用了ThreadLocal处理线程状态.
  2. 通过注释收集订阅信息的过程, 主要集中在SubscriberMethodFinder
  3. 中断订阅信息执行的方式
  4. 采用不同线程执行方法的实现方式

最后, 其实看commit的历史也挺有收获的 :D, 希望对大家有帮助.

推荐阅读更多精彩内容