EventBus 事件总线项目库源码分析

Posted by boredream on March 11, 2016

简单介绍

事件总线是一种设计 这个项目是greenrobot的一个开源库, 比较火

感觉属于订阅者模式, 和LocalBroadcast本地广播, 以及响应式编程等都有点像 发送者只管发出去, 订阅者不管谁发的只管接收使用, 一对多~ 而且重点在于解耦

使用很简单, 但还是被3.0.0小坑了下 最新的3.0.0版本, 使用标签取代了以前的方法名

获取实例还是一样 getDefault获取 然后订阅的地方, 先注册 比如页面中控件需要订阅某个事件可以及时响应更新, 则可以在页面onCreate的时候注册 然后在页面销毁的时候取消注册

1
2
EventBus.getDefault().register(this);
EventBus.getDefault().unregister(this);

然后复写接收方法

1
2
3
4
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(String s) {
    // do something
}

ThreadMode 表示不同的线程

1
2
3
4
@Subscribe(threadMode = ThreadMode.MainThread) //在ui线程执行
@Subscribe(threadMode = ThreadMode.BackgroundThread) //在后台线程执行
@Subscribe(threadMode = ThreadMode.Async) //强制在新的后台执行
@Subscribe(threadMode = ThreadMode.PostThread) //默认方式, 在发送线程执行

方法名不再固定名称, 可以随便取, 使用标签进行申明线程范围

async比较特别, 不在发送线程也不在主线程中执行, 而是另起一个单独的子线程 耗时任务比如网络请求可以使用这种方式 EventBus是会使用一个线程池更加有效的反复利用这些完成后的线程, 要避免短时间内大量的启动这样的单独子线程~

然后在需要的地方进行事件的发送 可以在主线程或者子线程中发送, 接收地方会根据不同ThreadMode进行线程分发处理~

1
2
3
4
5
6
7
8
EventBus.getDefault().post("main");

new Thread(new Runnable() {
    @Override
    public void run() {
        EventBus.getDefault().post("new thread");
    }
}).start();

此外发送的时候还可以指定 sticky 以及优先级 priority


源码分析

首先getDefault获取实例

果断是一个单例模式

1
2
3
4
5
6
7
8
9
10
11
/** Convenience singleton for apps using a process-wide EventBus instance. */
    public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }

然后是regist注册

首先会遍历注册类其中的全部方法, 然后根据注解获取到订阅方法 同时获取到方法名,参数,注解中表明的线程类型等所有信息 然后将方法存至集合中, 保存的过程中还会根据优先级 priority 进行顺序插入集合 最终会封装到一个Map中

1
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;

Map的key就是订阅者的Class类型 而value是一个集合, 其中是Subscription就是具体的每一个订阅元素 Subscription类中包含了订阅者对象以及订阅方法

最后是发送

先从线程池中取出一个闲置线程, 然后将待发送的事件加入到其发送队列中 然后判断当前线程是否为主线程, 最后再遍历订阅者, 判断订阅者的线程类型 最后进行invokeSubscriber方法让订阅者方法利用反射进行回调执行

EventBus在初始化的时候会分别创建一个主线程的Poster和子线程的Poster 子线程的Poster为runnable类型 而主线程的Poster则继承Handler, 并且其Looper使用Looper.getMainLooper() 反射回调订阅方法时会判断, 如果方法的ThreadMode是Main需要在子线程中执行,

  • 如果事件发送本身就是子线程则直接回调,
  • 如果发送处为子线程,则利用这个主线程中的handler将事件发送到主线程中进行回调~

EventBus和他的类似框架区别 一是在于订阅者元素一个是方法~ 其它有些是类或者说是接口~ 而EventBus最主要的是利用了反射区回调invoke这些方法, 因此最大的好处是不需要写一个一个的接口类, 所有的类都可以直接加入到订阅者集合中

done