概述
EventBus是一款对Android的发布/订阅事件总线的常用的开源框架,在日常开发中,使用起来非常方便。能够帮助我们很简洁的实现组件之间的通信,只需要几行代码即可搞定。
简介
EventBus工作时,发布者将一个个事件(events)发送到事件总线上,EventBus会根据已经注册的订阅者(subscribers)去分发这些事件,将发布者发布的事件传递给订阅者,订阅者收到之后进行进一步的处理,总体为观察者模式。
图解

如上图所示,发布事件到EventBus上,再由EventBus去分发给具体的订阅者。
所在使用时,我们基本分为三步:订阅、发布事件、接收并处理事件。
优点
- 简化组件间的通信
- 分离发送方和接收方
- 避免复杂和容易出错的依赖关系及生命周期
- 指定线程
- 使代码更加简洁
- 快速、微小、使用广
- 可以设置优先级
基本使用
添加依赖
在AndroidStudio中
直接在build.gradle文件的dependencies{}中添加对应的依赖:
compile 'de.greenrobot:eventbus:3.0.0-beta1'
Maven
<dependency>
<groupId>org.greenrobot</groupId>
<artifactId>eventbus</artifactId>
<version>3.0.0</version>
</dependency>
其他
还可以通过下载jar包添加到对应工程的lib目录下。
注册成为订阅者
将当前类注册成为订阅者,对应观察者模式中的观察者,当有发布者将事件发布传递过来时,就会接受到该事件,从而进行处理事件。一般在类初始化时注册,在Android中,如在Activity中我们在onCreat()方法中去注册,例如:
EventBus.getDefault().register(this);
当然,注册之后,当我们的Activity销毁时,需要取消订阅,防止造成内存泄漏:
EventBus.getDefault().unregister(this);
声明订阅的方法
在EventBus 3.0中,我们可以自定义订阅方法的方法名(在之前需要使用固定的onEvent(Object event)方法来作为订阅方法),但是需要添加注解@Subscribe,这里需要注意方法必须是public的权限,例如:
@Subscribe
public void onEvent(String event) {
// 处理事件
...
}
发送事件
发送事件的方法也很简单,一句代码搞定:
EventBus.getDefault().post("Hello EventBus!");
这样就将该事件发送到EventBus上,注册了对应的订阅者就可以接收到该事件。
到这里我们其实可以发现这个优先类似于Android中的广播机制,订阅,发送广播,接收广播处理事件,只是比广播实现代码相对简单一些,其实EventBus还有更多的有点,例如指定线程执行等。
进阶使用
线程模型
在EventBus中是可以指定事件处理所在的线程的,即想要让该事件在哪个线程中运行,例如:当我们接收到一个事件,需要我们去调用网络获取数据,由于是耗时操作,所以需要开启子线程去执行,这时我们就可以直接指定该事件在哪个线程去执行。
指定的方法也很简单,就在注解后面声明
@Subscribe(threadMode = ThreadMode.BackgroundThread)
点开源码看一下ThreadMode这个类,其实是个枚举类,定义了事件执行的线程模型:
public enum ThreadMode {
/**
* ...
*/
PostThread,
/**
* ...
*/
MainThread,
/**
* ...
*/
BackgroundThread,
/**
* ...
*/
Async
}
这里我们解释一下这四种线程模型:
- ThreadMode.PostThread
顾名思义,发送线程,当我们在一个线程中发布了事件时,如果指定为这种线程模型,该事件将直接在该线程中去执行,即哪里发送哪里执行,两者在同一个线程中执行。
使用这种线程模型需要注意的是,当我们在主线程发布事件时,如果处理该事件是耗时操作,直接在主线程执行可能会引起ANR。
- ThreadMode.MainThread
这个线程模型大家一看就会明白,主线程。在Android中,处理UI显示问题需要在主线程中执行,当我们在子线程中通过耗时操作获取到数据后,需要更新UI,这是需要将事件执行为主线程去执行。
但要注意不要在该线程中去执行耗时操作。
- ThreadMode.BackgroundThread
如果该事件是从UI线程中发布出来的,那么处理事件时会开启一个新的子线程去执行;
如果该事件是从子线程中发布出来的,那么处理事件将会直接在该子线程中去执行;
指定为该线程模型时,不能进行UI更新操作。
- ThreadMode.Async
指定为该线程模型时,无论事件是从哪个线程中发布出来的,执行处理事件都会重新开启一个线程去执行,该模型中也禁止处理UI更新操作。
对于这几种线程模型,可以写个Demo,分别制定不同的线程模型,将当前执行的线程名打印出来看一下,这里就不再演示。
粘性事件
广播有粘性广播,当然事件也会有粘性事件。
粘性事件,即事件已经发布之后,再订阅该事件,也能够接受到该事件。
发送粘性事件
发送普通事件时直接调用post方法,在发布粘性事件时,需要调用postSticky方法:
EventBus.getDefault().postSticky("粘性事件");
订阅粘性事件
订阅粘性事件时,需要在注解后面声明该事件为粘性事件,即:
@Subscribe(sticky = true)
public void XXX(String event) {
// 处理事件
......
}
这里需要注意的是,虽然可以接受粘性事件,但是,只能接受最后一条粘性事件,即如果发送了N条事件,但是订阅者只能接收到最后发送的一条事件。
优先级
事件类似于广播一样,也具有优先级,当多个订阅者订阅同一个事件时,优先级越高,越优先获取事件。
使用时也是在注解后面声明该事件的优先级,例如:
@Subscribe(priority = 100)
public void onEvent(Stirng event){
// 处理事件
...
}
事件拦截
有了优先级当有就会想到是否可以在优先级高的订阅者将该事件拦截下来,当然是可以的。
在事件处理方法中,可以调用cancelEventDelivery()方法阻止该事件的继续传递,达到拦截的效果。
@Subscribe(priority = 100)
public void onEvent(Stirng event){
// 处理事件
...
// 处理完事件,不希望该事件继续传递,拦截
EventBus.getDefault().cancelEventDelivery(event);
}