EventBus
事件总线.以观察者模式实现,消息推送/订阅.用于Android组件之间相互通信
项目地址:https://github.com/greenrobot/EventBus Docment:http://greenrobot.org/eventbus/documentation/how-to-get-started/
是什么?有什么用?解决了什么问题?
有点类似于广播,可以这样去理解.方便组件之间相互通信,Activity,Service,Fragment...通信这个词有点过于官方,通俗点的说就是在他们之间发消息,传输数据.例如,你在个人主页编辑头像的界面修改了头像,这时候其它页面的头像也需要去修改,这时候可以试试EventBus.
怎么用?
- 添加依赖
- 使用三歩曲:
- 定义事件类
- 注册事件
- 发送事件
添加依赖
compile 'org.greenrobot:eventbus:3.0.0'
使用三步曲:
1,定义事件类
public static class MessageEvent {
/* Additional fields if needed */
}
2.注册事件
- 注册本组件的EventBus:EventBus.getDefault().register(this);
- 添加@Subscribe注解:在函数上添加,表示这个函数是接收消息的回调的函数,函数名是自定义的
- 注销本组件的EventBus:EventBus.getDefault().unregister(this);
Note:一个事件是可以有多个接收者(订阅者),这里只是写一个做为示例
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注册
EventBus.getDefault().register(this);
}
//加上Subscribe注解,这个方法会在事件发出后收到回调,方法名是自定义的
@Subscribe
public void onMessageEvent(MessageEvent event) {
Log.i(TAG, "onMessageEvent: ");
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
3.发送事件
这个方法可以写在View的点击事件上,也可以写在网络请求的回调中...任何你想要的地方
EventBus.getDefault().post(new MessageEvent());
这里顺便吐槽下官方示例代码:
如果你打算把注册写在onStart中,请在前面加上判断
@Override
public void onStart() {
super.onStart();
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
}
}
上面是EventBus的基本使用流程,其实这才开始:
- 在事件中传递数据
- 指定事件接收线程
- 发送黏性事件Sticky Events
- 接收事件的优先级别
- 中止事件传递
- 订阅者索引
传递数据
不过,上面只是发了一个空的消息,没有传递任何的数据,怎么做呢? 比如:我修改了用户的头像,上传到服务器,服务器返回一个Url,这时候我希望其它界面的头像也更改,这时候我要把这个url传到其它界面:
1.只需要去修改定义事件类中的构造函数,增加一个参数,在加上set和get方法,如下:
public class UpdateHeadPicEvent {
private String mUrl;
public UpdateHeadPicEvent(String url) {
this.mUrl = url;
}
public String getUrl() {
return mUrl;
}
public void setUrl(String url) {
mUrl = url;
}
}
2.在发送事件的地方,使用这个带参的构造去创建对象:
EventBus.getDefault().post(new UpdateHeadImgEvent(url));
3.在接收消息的回调中用get方法去获取
@Subscribe
public void onUpdateHeadPicEvent(UpdateHeadPicEvent event) {
String url = event.getUrl();
Log.i(TAG, "onUpdateHeadPicEvent: " + url);
}
Note:这里只是用了一个String的Url做参考,可以传递的数据还有很多,List集合,Bean对象...
指定事件接收的线程
前面说了加上@Subscribe注解,这个函数在消息推送之后会被回调,其实这个注解还有几个属性,其中threadMode能为这个函数指定线程,如果不写,也会有个默认值:ThreadMode.POSTING,意思是和发送事件所在线程一样
@Subscribe(threadMode = ThreadMode.POSTING)
public void onUpdateHeadPicEvent(UpdateHeadPicEvent event) {
String url = event.getUrl();
Log.i(TAG, "onUpdateHeadPicEvent: " + url);
}
ThreadMode列表
- ThreadMode.POSTING:和发送事件在同一个线程
- ThreadMode.MAIN:主线程
- ThreadMode.BACKGROUND:子线程
- ThreadMode.ASYNC:异步线程
发送黏性事件Sticky Events
上面示例代码所说的情况是:当发送消息推送者推送消息的时候,订阅者会立马收到消息,它会把消息推送给它所有的订阅者.注意后面这句话:如果你想在消息推送完成之后,让新加入的订阅者也能收到这条消息,这时候你可以试试Sticky Events,这个事件就像一个常驻广播,只要是有新的订阅者订阅了这个事件,就会收到消息.当然,有两点要求:
- 首先,发送的是黏性事件,代码将post改为postSticky
// EventBus.getDefault().post(new MessageEvent());
EventBus.getDefault().postSticky(new MessageEvent());
然后,订阅者要声明自己能够接收到黏性事件的消息:代码中@Subscribe注解中的sticky值为true,满足了这两点,就能愉快的玩耍了.
@Override protected void onStart() { super.onStart(); if (!EventBus.getDefault().isRegistered(this)) { EventBus.getDefault().register(this); } } @Subscribe(sticky = true) public void onMessageEvent(LoginEvent event) { Log.i(TAG, "onMessageEvent: 我是sticky event 收到消息"); } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); }
测试Log日志
接收事件的优先级别
EventBus可以定义接收事件方的优先级别,在@Subscribe注解中有一个priority的参数,默认值是0,可以自行配置1.2.3.4...数值越大优先级越低,会越晚收到消息
@Subscribe(priority = 0)
public void onUpdateHeadPicEvent(UpdateHeadPicEvent event) {
String url = event.getUrl();
Log.i(TAG, "onUpdateHeadPicEvent: " + url);
}
中止事件传递
类似于有序广播,优先级高的订阅者,可以终止事件向下传递,EventBus也提供了此功能
@Subscribe(priority = 0)
public void onUpdateHeadPicEvent(UpdateHeadPicEvent event) {
EventBus.getDefault().cancelEventDelivery(event) ;
}
订阅者索引
这个新特性是在EventBus 3.0推出,简单的说:利用annotationProcessor去生成一个关于订阅者的索引类,保存订阅者的相关信息. 有什么用?提高效率,注册从运行时的反射,转移到了编译时 怎么用?两种方式:
- 在gradle版本2.2.0以前使用:Android-apt
- 在gradle版本2.2.0以上使用:annotationProcessor
这里说annotationProcessor的方式,现在新建项目一般都在2.2.0以上:
添加好Gradle设置之后,重新build项目,就会为你生成这样的类:MyEventBusIndex
用法:将它配置应用于默认的EventBus,调用下面代码:可放在Application的onCreate中调用
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
未添加前和添加后我分别做了三次测试,注册完成的时间对比,速度快了不止一倍,这还是只有两个订阅者的时候,如果订阅订阅者更多呢,
//未添加前
I/Subscriber1Activity: onMessageEvent: register start 1491892487664
I/Subscriber1Activity: onMessageEvent: register end 1491892487666
I/Subscriber1Activity: onMessageEvent: register start 1491892568177
I/Subscriber1Activity: onMessageEvent: register end 1491892568180
I/Subscriber1Activity: onMessageEvent: register start 1491892715342
I/Subscriber1Activity: onMessageEvent: register end 1491892715344
//添加后
I/Subscriber1Activity: onMessageEvent: register start 1491892648185
I/Subscriber1Activity: onMessageEvent: register end 1491892648186
I/Subscriber1Activity: onMessageEvent: register start 1491892814517
I/Subscriber1Activity: onMessageEvent: register end 1491892814518
I/Subscriber1Activity: onMessageEvent: register start 1491892868879
I/Subscriber1Activity: onMessageEvent: register end 1491892868880
在Lib的model中使用:
build.gradle也要添加上图中同样的参数,在上图中,这个参数是自定义的,不同的model可以为他生成不同的索引类:
arguments = [eventBusIndex: 'com.example.myapp.MyEventBusIndex']
更改默认配置也需要多添加一行代码:
EventBus eventBus = EventBus.builder()
.addIndex(new MyEventBusAppIndex())
.addIndex(new MyEventBusLibIndex())
.installDefaultEventBus();