EventBus是一款Android下的发布/订阅事件总线机制。可以代替Intent、Handler、Broadcast等在Fragment、Activity之间传递消息。
优点:开销小,代码优雅。将发送者和接受者解耦。
主要区别在订阅函数的不同
EventBus2.x中只暴露了四个方法供用户调用,分别是
EventBus3.0中必须使用注解,例如:
@Subscribe(threadMode = ThreadMode.Async, sticky = true, priority = 1)
public void firstEvent(FirstEvent event) {
Log.e("TAG", "Async" + Thread.currentThread().getName());
}
好处在于订阅函数可以随便起名字,其他与2.x没什么不同。
这里Subscribe中的key需要解释一下含义,Subscribe中可以传三种值:
ThreadMode:这是个枚举,有四个值,决定订阅函数在哪个线程执行
sticky:默认为false,如果为true,当通过postSticky
发送一个事件时,这个类型的事件的最后一次事件会被缓存起来,当有订阅者注册时,会把之前缓存起来的这个事件直接发送给它。使用在比如事件发送者先启动了,订阅者还没启动的情况。
当默认的EventBus不足以满足需求时,EventBusBuilder就上场了,EventBusBuilder允许配置各种需求的EventBus
例如1:
当没有subscribers的时候,eventbus保持静默:
EventBus eventBus = EventBus.builder().logNoSubscriberMessages(false)
.sendNoSubscriberEvent(false).build();
例如2:
配置异常:
默认情况下:eventbus捕获onevent抛出的异常,并且发送一个SubscriberExceptionEvent 可能不必处理
EventBus eventBus = EventBus.builder().throwSubscriberException(true).build();
官方推荐:在application类中,配置eventbus单例,保证eventbus的统一
例如:配置eventbus 只在DEBUG模式下,抛出异常,便于自测,同时又不会导致release环境的app崩溃
EventBus.builder().throwSubscriberException(BuildConfig.DEBUG).installDefaultEventBus();
前面说的一般的post event,正常流程,必须是先register,然后post event,handle event才能起作用。但是当我们post event时,还没有subcriber怎么办?但是又想后注册的subscriber,能收到消息,这时sticky event就开始大显身手了。
Warning:EventBus会把最后一个sticky event记录在内存中,然后分发给subscriber
来看下官方的Demo
1 post sticky event:
EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));
2 启动一个新的Activity,准备subscriber,注册后,
所有的sticky subscriber的回调方法,会马上获得之前的sticky event
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
//注意这里sticky=true
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {
// UI updates must run on MainThread
textField.setText(event.message);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
如上所述,当subscriber注册后,最后一个sticky event会自动匹配。但是,有些时候,主动去检查sticky event会更方便,并且 sticky event 需要remove,阻断继续传递。
官方demo
//返回的是之前的sticky event
MessageEvent stickyEvent = EventBus.getDefault().removeStickyEvent(MessageEvent.class);
// Better check that an event was actually posted before
if(stickyEvent != null) {
// Now do something with it
}
2中sticky event使用方法都可行,看业务需要和个人习惯,选择合适的使用方法
大多数情况下,eventbus不需要改变线程优先级,或者取消event,但是不排除少数情况,需要改变线程优先级。
官方demo
//priority默认为0,不同ThreadMode下的分发流程不受优先级的影响
//优先级高的可以优先获得消息
@Subscribe(priority = 1);
public void onEvent(MessageEvent event) {
…
}
如果,不希望后续的subcriber收到消息,可以在收到消息后,调用cancelEventDelivery(Object event) 取消消息的后续传递。
官方demo
@Subscribe
public void onEvent(MessageEvent event){
// Process the event
…
EventBus.getDefault().cancelEventDelivery(event) ;
}
Note:一般情况下,event的取消发生在高优先级的subscriber
创建事件:
public class FirstEvent {
private String msg;
public FirstEvent(String msg){
this.msg = msg;
}
public String getMsg(){
return msg;
}
}
使用场景一:在Activity之间通信传值
在MainActivity的onCreate方法中注册,onDestroy方法中反注册
EventBus.getDefault().register(this);
EventBus.getDefault().unregister(this);
订阅函数,此处用来查看执行在哪个线程(注意,这里的函数名可以任取):
@Subscribe(threadMode = ThreadMode.Async, sticky = true, priority = 1)
public void onAsync(FirstEvent event) {
Log.e("TAG", "Async: " + Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.BackgroundThread)
public void onBackgroundThread(FirstEvent event) {
Log.e("TAG", "BackgroundThread: " + Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.MainThread)
public void onMainThread(FirstEvent event) {
Log.e("TAG", "MainThread: " + Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.PostThread)
public void onPostThread(FirstEvent event) {
Log.e("TAG", "PostThread: " + Thread.currentThread().getName());
}
在SecondActivity发送事件(主线程中发送):
EventBus.getDefault().post(new FirstEvent("啦啦啦"));
执行结果如下:
Async: pool-1-thread-1
MainThread: main
PostThread: main
BackgroundThread: pool-1-thread-2
如果是在子线程中发送:
new Thread(new Runnable() {
@Override
public void run() {
EventBus.getDefault().post(new FirstEvent("啦啦啦"));
}
}).start();
执行结果如下:
BackgroundThread: Thread-450
PostThread: Thread-450
Async: pool-1-thread-1
MainThread: main
如果先启动SecondActivity,后启动MainActivity:
@Override
public void onClick(View v) {
EventBus.getDefault().postSticky(new FirstEvent("啦啦啦"));
startActivity(new Intent(SecondActivity.this,MainActivity.class));
}
确实只有onAsync方法收到了消息。
至此对EventBus的试验基本就结束了,各位可以自行选择不同的ThreadMode值,让订阅函数执行在不同的线程。根据需要选择是否需要sticky=true。
完整的MainActivity和SecondActivity代码如下(xml文件就不贴了,就一个Button):
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EventBus.getDefault().register(this);
findViewById(R.id.btn).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this,
SecondActivity.class));
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
@Subscribe(threadMode = ThreadMode.Async, sticky = true, priority = 1)
public void onAsync(FirstEvent event) {
Log.e("TAG", "Async: " + Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.BackgroundThread)
public void onBackgroundThread(FirstEvent event) {
Log.e("TAG", "BackgroundThread: " + Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.MainThread)
public void onMainThread(FirstEvent event) {
Log.e("TAG", "MainThread: " + Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.PostThread)
public void onPostThread(FirstEvent event) {
Log.e("TAG", "PostThread: " + Thread.currentThread().getName());
}
}
public class SecondActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
findViewById(R.id.second).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().postSticky(new FirstEvent("Lai自星星的我"));
startActivity(new Intent(SecondActivity.this,MainActivity.class));
}
});
}
}
使用场景二:完美替换Handler,在主线程更新UI,如下示例-模拟下载显示进度条
:
public class MainActivity extends Activity { public ProgressBar progressBar = null; public int time = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread(new Runnable() { @Override public void run() { while (time<100){ time += 15; EventBus.getDefault().post(new TestEvent(time)); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } }); progressBar = (ProgressBar) findViewById(R.id.progressbar); EventBus.getDefault().register(this); } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); } @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(TestEvent event){ progressBar.setProgress(event.getMsg()); } }
当然EventBus的功能并不局限这两种,还可以替换各种CallBack回调接口、StrartActivityForResult()等功能。
EventBus封装类:
/** * @author * @version 1.0 * @date 2016-3-31 上午10:59:22 * @describe EventBusUtils工具类 */ public class EventBusUtils { public static void register(Object subscriber) { if (!EventBus.getDefault().isRegistered(subscriber)) { EventBus.getDefault().register(subscriber); } } public static void unregister(Object subscriber) { if(EventBus.getDefault().isRegistered(subscriber)){ EventBus.getDefault().unregister(subscriber); } } public static void sendEvent(EventBusEvent event) { EventBus.getDefault().post(event); } public static void sendStickyEvent(EventBusEvent event) { EventBus.getDefault().postSticky(event); } /** * 通过code码区分事件类型 */ public static final class EventCode { public static final int A = 0x111111; public static final int B = 0x222222; public static final int C = 0x333333; public static final int D = 0x444444; public static final int E = 0x555555; // other more } }
/** * @author * @version 1.0 * @date 2017/5/12 17:01 * @describe EventBus事件类 * * 通过泛型指定事件通信过程中的数据类型,code为事件码,使用的时候给不同的事件类型指定不同的code。 */ public class EventBusEvent<T> { private int code; private T data; public EventBusEvent(int code) { this.code = code; } public EventBusEvent(int code, T data) { this.code = code; this.data = data; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public T getData() { return data; } public void setData(T data) { this.data = data; } }
-keepattributes *Annotation*
-keepclassmembers class ** {
@org.greenrobot.eventbus.Subscribe ;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
(java.lang.Throwable);
}