背景
在Android
开发中数据传递的方式有很多种,常见的有
Intent
在页面间传递数据Handler
刷新UIBroadcast
传递消息
系统提供的API
在使用上会有些复杂。
举个示例:Handler发送数据并刷新UI
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
// 完成主界面更新,拿到数据
String data = (String) msg.obj;
textView.setText(data);
break;
default:
break;
}
}
};
private void getDataFromNet() {
new Thread(new Runnable() {
@Override
public void run() {
//耗时操作,完成之后发送消息给Handler,完成UI更新;
mHandler.sendEmptyMessage(0);
//需要数据传递,用下面方法;
Message msg = new Message();
//可以是基本类型,可以是对象,可以是List、map等;
msg.obj = "网络数据";
mHandler.sendMessage(msg);
}
}).start();
}
下面是EventBus
简单使用的伪代码
:
// 注册
EventBus.getDefault().register(this);
// 注销
EventBus.getDefault().unregister(this);
// 发送 MessageEvent 事件
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
// 接收 MessageEvent 事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
当然,EventBus
的出现不是为了取代系统API
,只是给我们提供了更多的选择。
在系统API
能轻松实现的情况下,就没必要引入EventBus
了,虽然它只有60k
。
接下来我们需要对EventBus
进行更进一步的了解,才能更好地使用。
定义
EventBus
是一个事件发布/订阅轻量级框架。相关的发布订阅可参考:发布订阅-维基百科。
关于观察者模式和发布订阅模式的谈论,可查看知乎这篇文章。
EventBus
的事件发布者不会将事件直接发给订阅者,而是将发布的事件分为不同的类型,订阅者可以选择只感兴趣的事件订阅。
使用过EventBus
的朋友回忆一下,确实是如此。没使用过EventBus
的朋友可以耐心往下看。
它有以下优点:
- 能够简化组件间的通信
- 有效地将事件发送者和订阅者解耦
- 能避免复杂的依赖性和生命周期问题
- 在
Fragment,Activity,Service, 后台线程
之间传递数据,性能更好。
EventBus
可以代替Android
传统的Intent,Handler,Broadcast 或接口函数
,
基本使用
使用步骤分为下面几步:
- 引入依赖
- 定义事件对象
- 事件订阅和解除订阅
- 发送事件
引入依赖
implementation 'org.greenrobot:eventbus:3.1.1'
定义事件对象
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}
事件订阅
事件不可重复订阅,一般我们在
onCreate
或者onStart
方法中订阅
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
解除事件订阅
事件不可重复解除订阅,一般我们在
onStop
或者onDestory
方法中解除订阅
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
发送事件
- 普通事件:需要先注册事件才能接收到已发出的事件
- 粘性事件:事件不需要提前注册也能接收到。
比如:A
页面跳转 B
页面传递参数hello
,
如果传递参数时使用粘性事件,也就是在A
页面发送数据,在B
页面注册事件。且接收粘性事件,那么B
可以接收到参数hello
如果传递参数时使用普通事件,那么B
可以接收不到参数hello
。因为普通参数需要注册才能收到消息。
接下来看普通事件和粘性事件的使用。
普通事件
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
// 在主线程展示 Toast 结果
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
粘性事件
EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));
// 在主线程刷新 UI
@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) {
// 移除某个事件
EventBus.getDefault().removeStickyEvent(stickyEvent);
// Now do something with it
}
// 移除全部事件
EventBus.getDefault().removeAllStickyEvents();
在接收数据时我们可以看到threadMode = ThreadMode.MAIN
指定了线程环境,EventBus
还提供了其他四种线程环境。
设置线程环境
ThreadMode.POSTING
,This is the default,和发布者处在同一个线程,避免线程阻塞ThreadMode.MAIN
,UI 线程,避免线程阻塞ThreadMode.MAIN_ORDERED
,called in Android’s main thread,有顺序的订阅,避免线程阻塞ThreadMode.BACKGROUND
,called in a background thread. 单后台线程,也是需要避免线程阻塞ThreadMode.ASYNC
,called in a separate thread,使用场景,网络请求,内部使用线程池去维护
设置事件优先级
事件的优先级类似广播的优先级,优先级越高优先获得消息。默认优先级是
0
//在 ui 线程执行 优先级 100
@Subscribe(threadMode = ThreadMode.MAIN, priority = 100)
public void onDataSynEvent(DataSynEvent event) {
Log.e(TAG, "event---->" + event.getCount());
}
总结
EventBus
的基本使用还是很简单的,主要分为三步
- 引入依赖
- 注册事件和接收事件
- 发送事件
注册事件需要和注销事件成对出现,否则会内存泄露。
而且注册事件要在onCreate
或者onStart
生命周期中注册,注销事件在onStop
或者onDestory
方法中。
发送事件分为普通事件和粘性事件。
- 普通事件只能在事件注册之后才能收到。
- 粘性事件能确保事件注册之后一定能接收到,粘性事件如果不需要了记得要移除。
- 粘性事件的移除又分为单个事件移除和全部事件移除。
END~