1. EventBus简介
EventBus是一种用于Android的事件发布-订阅总线,它简化了应用程序内各个组件之间进行通信的复杂度,尤其是碎片之间进行通信的问题,可以避免由于使用广播通信而带来的诸多不便。
EventBus github地址
1.1 三个重要角色
- Event:事件,它可以是任意类型,EventBus会根据事件类型进行全局的通知。
- Subscriber:事件订阅者,在EventBus 3.0之前我们必须定义以onEvent开头的那几个方法,分别是onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,而在3.0之后事件处理的方法名可以随意取,不过需要加上注解@subscribe,并且指定线程模型,默认是POSTING。
- Publisher:事件的发布者,可以在任意线程里发布事件。一般情况下,使用EventBus.getDefault()就可以得到一个EventBus对象,然后再调用post(Object)方法即可。
结构图如下:
从上图中可以看到这个库整体结构是基于生产者/消费者模式,也可以称呼为发布者/订阅者
1.2四种线程模式
EventBus3.0有四种线程模式,分别如下:
- POSTING:默认,表示事件处理函数的线程跟发布事件的线程在同一个线程。
- MAIN:表示事件处理函数的线程在主线程(UI)线程,因此在这里不能进行耗时操作。
- BACKGROUND:表示事件处理函数的线程在后台线程,因此不能进行UI操作。如果发布事件的线程是主线程(UI线程),那么事件处理函数将会开启一个后台线程,如果果发布事件的线程是在后台线程,那么事件处理函数就使用该线程。
- ASYNC:表示无论事件发布的线程是哪一个,事件处理函数始终会新建一个子线程运行,同样不能进行UI操作。
2.EventBus的使用
2.1添加依赖
要使用EventBus首先要添加依赖,在build.gradle中dependences里面添加如下:
implementation 'org.greenrobot:eventbus:3.1.1'
2.2基本使用
从EvnetBus的结构图来看,它的实现原理,跟我们日常生活中的微信公众号很类型,首先在使用的时候,我们需要向公众平台注册,注册完之后, 当生产者需要发布信息的时候,平台会帮我们把这些消息推送给订阅者,订阅者根据消息内容,进行不同处理操作。
使用流程如下:
EventBus基本使用包括三个步骤:定义事件,发布事件, 订阅事件
1.定义事件
事件可以是任意普通的Java对象,没有任何特殊的要求,如下:
public class MessageEvent {
private String message;
public MessageEvent(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
- 订阅事件
订阅者需要定义事件处理方法(也称为订阅者方法)。当发布对应类型的事件时,该方法将被调用。EventBus 3使用 @Subscribe 注解来定义订阅者方法。方法名可以是任意合法的方法名,参数类型为订阅事件的类型。如下代码所示:
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
...
}
订阅者还需要在总线上注册,并在不需要时在总线上注销。只有订阅者注册了,它们才会收到事件。在Android中,可以根据Activity或者Fragment的生命周期来注册和注销。例如:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initContentView();
// 注册订阅者
EventBus.getDefault().register(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 注销订阅者
EventBus.getDefault().unregister(this);
}
- 发布事件。
在需要的地方发布事件,所有订阅了该类型事件并已注册的订阅者将收到该事件。如下:
// 发布事件
EventBus.getDefault().post(new MessageEvent("Hello EventBus!"));
订阅事件的例子如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "MainActivity";
private TextView mTvMessage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initContentView();
// 注册订阅者
EventBus.getDefault().register(this);
}
private void initContentView() {
Button btnStart = findViewById(R.id.btn_main_start_activity);
mTvMessage = findViewById(R.id.tv_main_message);
btnStart.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_main_start_activity) {
SecondActivity.start(this);
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
Log.i(TAG, "message is " + event.getMessage());
// 更新界面
mTvMessage.setText(event.getMessage());
}
@Override
protected void onDestroy() {
super.onDestroy();
// 注销订阅者
EventBus.getDefault().unregister(this);
}
}
MainActivity订阅了MessageEvent事件。当接收到MessageEvent事件时,订阅者方法将打印日志消息,并更新界面上的TextView。
发布事件的例子如下:
public class SecondActivity extends AppCompatActivity implements View.OnClickListener {
public static void start(Context context) {
Intent intent = new Intent(context, SecondActivity.class);
context.startActivity(intent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
initContentView();
}
private void initContentView() {
findViewById(R.id.btn_second_post_event).setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_second_post_event) {
// 发布事件
EventBus.getDefault().post(new MessageEvent("Hello EventBus!"));
}
}
}
当点击发布事件的按钮时,SecondActivity将发布一个MessageEvent事件。
运行,点击MainActivity中的启动按钮启动SecondActivity,点击SecondActivity页面的发布事件按钮发布事件,最后回退到MainActivity,可看到界面上的TextView内容更行为“Hello EventBus”
订阅事件的代码如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initContentView();
// 注册订阅者
EventBus.getDefault().register(this);
}
private void initContentView() {
findViewById(R.id.btn_main_start_activity).setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_main_start_activity) {
SecondActivity.start(this);
}
}
@Subscribe(threadMode = ThreadMode.POSTING)
public void onMessageEventPosting(MessageEvent event) {
Log.i(TAG, "onMessageEventPosting(), current thread is " + Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEventMain(MessageEvent event) {
Log.i(TAG, "onMessageEventMain(), current thread is " + Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
public void onMessageEventMainOrdered(MessageEvent event) {
Log.i(TAG, "onMessageEventMainOrdered(), current thread is " + Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessageEventBackground(MessageEvent event) {
Log.i(TAG, "onMessageEventBackground(), current thread is " + Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessageEventAsync(MessageEvent event) {
Log.i(TAG, "onMessageEventAsync(), current thread is " + Thread.currentThread().getName());
}
@Override
protected void onDestroy() {
super.onDestroy();
// 注销订阅者
EventBus.getDefault().unregister(this);
}
}
MainActivity订阅了MessageEvent事件,定义了5个不同线程模式的订阅者方法。当接收到MessageEvent事件时,订阅者方法将打印当前所在的线程名。
2.3 粘性事件
黏性事件,就是指发送了该事件之后再订阅者依然能够接收到的事件。使用黏性事件的时候有两个地方需要做些修改。一个是订阅事件的地方,这里我们在先打开的Activity中注册监听黏性事件:
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onGetStickyEvent(MessageWrap message) {
String txt = "Sticky event: " + message.message;
getBinding().tvStickyMessage.setText(txt);
}
另一个是发布事件的地方,这里我们在新的开的Activity中发布黏性事件。即调用EventBus的postSticky方法来发布事件
private void publishStickyontent() {
String msg = getBinding().etMessage.getText().toString();
EventBus.getDefault().postSticky(MessageWrap.getInstance(msg));
ToastUtils.makeToast("Published : " + msg);
}
发布一个粘性事件之后,EventBus将一直缓存该粘性事件。如果想要移除粘性事件,那么可以使用如下方法:
// 移除指定的粘性事件
removeStickyEvent(Object event);
// 移除指定类型的粘性事件
removeStickyEvent(Class<T> eventType);
// 移除所有的粘性事件
removeAllStickyEvents();
发布粘性事件示例如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initContentView();
}
private void initContentView() {
findViewById(R.id.btn_main_post_event).setOnClickListener(this);
findViewById(R.id.btn_main_start_activity).setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_main_post_event:
// 发布粘性事件
EventBus.getDefault().postSticky(new MessageEvent("Hello EventBus!"));
break;
case R.id.btn_main_start_activity:
SecondActivity.start(this);
break;
default:
break;
}
}
}
当点击发布粘性事件的按钮时,MainActivity将发布一个MessageEvent粘性事件。
订阅粘性事件的示例代码如下所示:
public class SecondActivity extends AppCompatActivity {
private static final String TAG = "SecondActivity";
private TextView mTvMessage;
public static void start(Context context) {
Intent intent = new Intent(context, SecondActivity.class);
context.startActivity(intent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
initContentView();
// 注册订阅者
EventBus.getDefault().register(this);
}
private void initContentView() {
mTvMessage = findViewById(R.id.tv_second_message);
}
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onMessageEvent(MessageEvent event) {
Log.i(TAG, "message is " + event.getMessage());
// 更新界面
mTvMessage.setText(event.getMessage());
// 移除粘性事件
EventBus.getDefault().removeStickyEvent(event);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 注销订阅者
EventBus.getDefault().unregister(this);
}
}
SecondActivity订阅了MessageEvent粘性事件。当接收到MessageEvent粘性事件时,订阅者方法将打印日志消息,并更新界面上的TextView,最后移除该粘性事件。
3.EventBus事件的优先级
EventBus支持在定义订阅者方法时指定事件传递的优先级。默认情况下,订阅者方法的事件传递优先级为0。数值越大,优先级越高。在相同的线程模式下,更高优先级的订阅者方法将优先接收到事件。注意:优先级只有在相同的线程模式下才有效。
指定事件传递优先级的示例如下所示:
@Subscribe(priority = 1)
public void onMessageEvent(MessageEvent event) {
...
}
可以在高优先级的订阅者方法接收到事件之后取消事件的传递。此时,低优先级的订阅者方法将不会接收到该事件。注意: 订阅者方法只有在线程模式为ThreadMode.POSTING时,才可以取消一个事件的传递。
取消事件传递的示例如下所示:
@Subscribe(threadMode = ThreadMode.POSTING, priority = 1)
public void onMessageEvent(MessageEvent event) {
...
// 取消事件传递
EventBus.getDefault().cancelEventDelivery(event);
}
订阅事件并设置5个优先级的示例如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initContentView();
// 注册订阅者
EventBus.getDefault().register(this);
}
private void initContentView() {
findViewById(R.id.btn_main_start_activity).setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_main_start_activity) {
SecondActivity.start(this);
}
}
@Subscribe(threadMode = ThreadMode.POSTING, priority = 1)
public void onMessageEvent1(MessageEvent event) {
Log.i(TAG, "onMessageEvent1(), message is " + event.getMessage());
}
@Subscribe(threadMode = ThreadMode.POSTING, priority = 2)
public void onMessageEvent2(MessageEvent event) {
Log.i(TAG, "onMessageEvent2(), message is " + event.getMessage());
// 取消事件
EventBus.getDefault().cancelEventDelivery(event);
}
@Subscribe(threadMode = ThreadMode.POSTING, priority = 3)
public void onMessageEvent3(MessageEvent event) {
Log.i(TAG, "onMessageEvent3(), message is " + event.getMessage());
}
@Subscribe(threadMode = ThreadMode.POSTING, priority = 4)
public void onMessageEvent4(MessageEvent event) {
Log.i(TAG, "onMessageEvent4(), message is " + event.getMessage());
}
@Subscribe(threadMode = ThreadMode.POSTING, priority = 5)
public void onMessageEvent5(MessageEvent event) {
Log.i(TAG, "onMessageEvent5(), message is " + event.getMessage());
}
@Override
protected void onDestroy() {
super.onDestroy();
// 注销订阅者
EventBus.getDefault().unregister(this);
}
}
在MainActivity中定义了5个优先级,当接收到事件时将会打印方法中输出日志,同时在优先级为2的方法中取消了事件的传递
发布事件的示例代码如下:
public class SecondActivity extends AppCompatActivity implements View.OnClickListener {
public static void start(Context context) {
Intent intent = new Intent(context, SecondActivity.class);
context.startActivity(intent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
initContentView();
}
private void initContentView() {
findViewById(R.id.btn_second_post_event).setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_second_post_event) {
// 发布事件
EventBus.getDefault().post(new MessageEvent("Hello EventBus!"));
}
}
}