EventBus学习-基础使用
EventBus系列解析(基于3.2.0)
简介
官法对EventBus的定义为
EventBus is a publish/subscribe event bus for Android and Java.
即应用在java和android系统中基于 发布/订阅 的事件总线,通俗点理解就是一种轻量级的广播机制,它简化了程序中各个组件之间的通信。
image.png
目前最新版本为3.2.0
,如需引用需添加如下依赖:
implementation 'org.greenrobot:eventbus:3.2.0'
常规用法
**step1 : ** 定义事件类
事件类必须为简单的java数据类,不能包含任何的业务方法。
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}
**step2 : ** 订阅事件
在需要响应第一步中所定义事件的类(即事件订阅者)中实现处理该事件的方法,并使用@Subscribe
标记
@Subscribe
public void onMessageEvent(MessageEvent event) {
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
订阅者同时需要在合适的时机在事件总线中 注册/注销,只有当订阅者在事件总线中注册了,才会收到消息
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
**step3 : ** 发布事件
在应用中任何一个地方发送事件,所有订阅了该事件的地方都会收到调用
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
进阶用法
线程切换
EventBus允许订阅者指定处理事件的方法在哪个线程执行,只需在@Subscribe
注解中添加threadMode
参数即可
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
threadMode的值是一个枚举类型,只能指定为 ThreadMode.POSTING,ThreadMode.MAIN,ThreadMode.MAIN_ORDERED,ThreadMode.BACKGROUND,ThreadMode.ASYNC其中的一个,它们的含义分别为
- ThreadMode.POSTING:默认模式,订阅者会和消息的发送方执行在同一个线程,事件传递和所有订阅用户被调用是同步完成,不存在线程切换
- ThreadMode.MAIN:订阅者会在android主线程中被调用,如果事件本身是在主线程发送的,订阅者会被立即调用阻塞主线程,如果是在其他线程发送的,则会加入队列中,依次发送执行,如果是非Android环境,表现同
ThreadMode.POSTING
- ThreadMode.MAIN_ORDERED:订阅者会在android主线程中被调用,与
ThreadMode.MAIN
不同的是,不论是在哪发送的事件,都会放入队列中依次执行,不会阻塞主线程 - ThreadMode.BACKGROUND:订阅者会在后台执行,如果事件不是在主线程发送的,订阅者会被立即执行,如果是在主线程发送的,订阅者会在一个单独的后台线程执行。
- ThreadMode.ASYNC:订阅者会在一个单独的线程中立即执行。
使用编译时注解
在上述步骤中,订阅事件时我们使用了@Subscribe
注解去标识订阅者方法,在默认情况下会在运行时使用Java的反射机制去解析订阅者的整个class,找到并记录所有被标记的方法,在事件发送后进行调用,众所周知,Java的运行时反射机制比较耗费性能,所以在EventBus 3.0 中提供了编译时的注解处理器来解决这个问题,通过在编译时生成订阅者方法索引来避免运行时通过反射查找订阅者,这样更加的高效,而且避免了反射带来的性能消耗和crash。
在java语言项目中,可以通过在模块级的build.gradle
文件中添加以下配置使用注解处理器
android {
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
// apt参数,key 为固定值,value 为生成的java类的包名和类名
arguments = [ eventBusIndex : 'com.example.myapp.MyEventBusIndex' ]
}
}
}
}
dependencies {
def eventbus_version = '3.2.0'
implementation "org.greenrobot:eventbus:$eventbus_version"
annotationProcessor "org.greenrobot:eventbus-annotation-processor:$eventbus_version"
}
在kotlin项目或者kotlin/java混编项目中,可以通过在模块级的build.gradle
文件中使用kapt
apply plugin: 'kotlin-kapt' // ensure kapt plugin is applied
dependencies {
def eventbus_version = '3.2.0'
implementation "org.greenrobot:eventbus:$eventbus_version"
kapt "org.greenrobot:eventbus-annotation-processor:$eventbus_version"
}
kapt {
arguments {
// apt参数,key 为固定值,value 为生成的java类的包名和类名
arg('eventBusIndex', 'com.example.myapp.MyEventBusIndex')
}
}
完成上面的配置之后,Rebuild项目,在对应模块的/build/generated/source/apt(kapt) 目录下面就会生成com.example.myapp.MyEventBusIndex
索引文件,其中的 com.example.myapp
建议在配置时修改为自己的包名。
配置完成之后可以通过 EventBus.builder().addIndex(index) 方法生成一个有索引的EventBus实例
EventBus eventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();
也可以通过 EventBus.builder().addIndex(index).installDefaultEventBus()方法将这个实例设置为默认的EventBus
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
// Now the default instance uses the given index. Use it like this:
EventBus eventBus = EventBus.getDefault();
如果项目中使用的其他架包中也生成了EventBus的索引,则可以一并加入
EventBus eventBus = EventBus.builder()
.addIndex(new MyEventBusAppIndex())
.addIndex(new MyEventBusLibIndex()).build();
粘性事件
在某些情况下,事件的发生及发送是在订阅者订阅该事件之前的,
如果需要使用粘性事件,首先在事件发送时需要使用postSticky
方法
EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));
在订阅事件时同样需要标注sticky=true
// UI updates must run on MainThread
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {
textField.setText(event.message);
}
需要注意的是,所有的粘性事件当不在使用时,必须要手动移除,否则每次订阅了的类在注册时都会收到该事件
MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class);
// Better check that an event was actually posted before
if(stickyEvent != null) {
// "Consume" the sticky event
EventBus.getDefault().removeStickyEvent(stickyEvent);
// Now do something with it
}
优先级事件
在同一个处理线程中,高优先级的订阅者将会比其他低优先级的订阅者更先接收到消息,通过proority
可以给订阅者指定优先级,不指定的话默认为0
@Subscribe(priority = 1);
public void onEvent(MessageEvent event) {
...
}