compile 'org.greenrobot:eventbus:3.1.1'
先定义事件VO,和普通的Java Bean没有区别:
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}
使用@Subscribe这个注解,方法名不做任何限制:
// 接收者在UI线程中执行操作
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
//接收者与发送者在同一个线程中
@Subscribe
public void handleSomethingElse(SomeOtherEvent event) {
doSomethingWith(event);
}
别忘注册和取消注册事件,这可以防止内存泄露:
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
可以在任何地方发送一个事件:
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
这是EventBus的默认工作模式,发布者接收者在同一个线程中,需要注意的是接收者的逻辑不能太复杂,因为有可能阻塞主线程。
// Called in the same thread (default)
// ThreadMode is optional here
@Subscribe(threadMode = ThreadMode.POSTING)
public void onMessage(MessageEvent event) {
log(event.message);
}
顾名思义,事件按序发送。只有事件处理完成了,才会接收事件(官网文档前后矛盾,后续自己验证哪个订阅先执行吧),适合修改界面等敏感操作。
订阅者在后台线程中执行逻辑,如果事件发送者不在主线程那么会直接复用当前线程,如果发送者在主线程,那么EventBus用一个线程来按顺序处理事件,所以接收者也不要在这种模式下为所欲为,因为可能阻塞后台线程(个人感觉鸡肋,不如不要)。
为所欲为吧,专为耗时操作设计。事件接收及发送均无需等待,要慎重,避免开启过多线程, EventBus 使用线程池来高效复用线程。
就是事件发送了,但是我现在注册也要收到这个事件。
看一下例子吧:
假设现在发送一个事件:
EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));
现在启动一个新的Activity,相关代码如下:
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
// UI updates must run on MainThread
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {
textField.setText(event.message);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
有的时候你可能并不需要注册EventBus,只是要获得这个粘性事件:
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
}
removeStickyEvent方法很有意思,如果你将事件class穿进去,他会返回先前持有的粘性事件,使用这个特性,上述代码可以这样修改:
MessageEvent stickyEvent = EventBus.getDefault().removeStickyEvent(MessageEvent.class);
// Better check that an event was actually posted before
if(stickyEvent != null) {
// Now do something with it
}
是不是简洁了很多?当然前提是你需要杀掉这个粘性事件。
大部分情况下不需要这样做,但一些场景可能需要这样做:当App处于前台时,一个事件可能导致UI做出改变,但是App不可见时需要另外一种逻辑。
@Subscribe(priority = 1);
public void onEvent(MessageEvent event) {
...
}
注意:高优先级的先接收到事件,默认为0,但是只有ThreadMode相同时才有效,即不切换线程模式。
// Called in the same thread (default)
@Subscribe
public void onEvent(MessageEvent event){
// Process the event
...
// Prevent delivery to other subscribers
EventBus.getDefault().cancelEventDelivery(event) ;
}
事件通常被高优先级的订阅者取消,取消事件的方法必须处于 ThreadMode.PostThread模式下。