EventBus是最近接手的一个项目上在用的开源库,但是我这个EventBus菜鸟,之前还没用过,还没好好感受过它的好处,前几天刚刚看完源码,对EventBus有了一个大体的了解,看完源码之后,感觉此库真是好处多多啊,不吹不黑,不服来辩,哈哈哈,不吹了,根据官方doc,记录一下EventBus的使用。
使用一个开源库,我们总要知道他的优势所在,要不然那么多开源库,为毛非要用这个,你说是这个理不。那我们就看一下他的优势所在,
想知道官方的介绍的可以去这里查看:EventBus官方介绍
EventBus是安卓发布/订阅事件总线的优化
翻译过来其实也就这么核心几条:
1. 简化组件间的通信
(1).对发送和接受事件解耦
(2).可以在Activity,Fragment,和后台线程间执行
(3).避免了复杂的和容易出错的依赖和生命周期问题
2. 让你的代码更简洁
3. 更快
4. 更轻量(jar包小于50K)
5. 实践证明已经有一亿多的APP中集成了EventBus
6. 拥有先进的功能比如线程分发,用户优先级等等
盗图一张:
1. 添加gradle依赖
compile 'org.greenrobot:eventbus:3.0.0'
Events 就是一个普通的JavaBean,没有任何特殊要求,例如:
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}
准备subcriber的回调method,来处理post event,从EventBus_3开始,用注解@Subscribe来定义subscriber的回调method,方法名可以任意定义
例如:
// This method will be called when a MessageEvent is posted
@Subscribe
public void onMessageEvent(MessageEvent event){
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
// This method will be called when a SomeOtherEvent is posted
@Subscribe
public void handleSomethingElse(SomeOtherEvent event){
doSomethingWith(event);
}
Subscribers与BroadcastReceiver类似,需要register和unregister,只有注册了EventBus,回调方法才起作用,在Android中,一般与Activity的生命周期绑定在一起
官方demo:
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
前面准备好,这里就可以任意post event。所有已注册EventBus的subscriber只要event_type相匹配,都可以收到该event
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
当牵扯到线程间通讯时,特别是,主线程,后台线程,耗时操作线程,等线程间的通讯时,我们就必须倍加小心,好在EventBus很强大,已经考虑到了,我们只需要根据具体的需求去配置,不同的线程模式ThreadMode即可:
ThreadMode源码:
public enum ThreadMode {
POSTING,
MAIN,
BACKGROUND,
ASYNC;
}
接着,逐一分析下,各个模式适合的场景:
这个模式最简单,也是EventBus默认的模式,也就是说:post event和handle event在同一个线程
@Subscribe(threadMode = ThreadMode.POSTING) // ThreadMode is optional here
//默认为Posting,可以不指定
public void onMessage(MessageEvent event) {
log(event.message);
}
当指定threadMode=Main时,此时,handle event是运行在UI线程的,
如果,post event也是在UI线程,就跟Posting模式一样,
Warning:使用此模式,不能堵塞UI线程
// Called in Android UI's main thread
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(MessageEvent event) {
textField.setText(event.message);
}
当指定threadMode=Background时,
如果 post event不在UI线程,那么handle event 会在此线程回调;
如果 post event在UI线程,EventBus使用一个后台线程,按顺序分发所有事件。
Warning:使用此模式,不能堵塞后台线程
// Called in the background thread
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessage(MessageEvent event){
saveToDisk(event.message);
}
当指定threadMode=Async时,
handle event始终独立于UI线程和post event所在的线程,即:和post event 不在同一线程,
也不在UI线程。此模式适合耗时任务:e.g.:网络链接。
Warning:避免触发大量的长时间运行的异步线程,来限制并发线程的数量。
EventBus使用Thread pool高效 的使用线程
// Called in a separate thread
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessage(MessageEvent event){
backend.send(event.message);
}
当默认的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
-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);
}
关于AsyncExecutor的用法,还是看官方文档吧,因为这个我也没用过
这是eventbus3.0新增的功能,是对原有功能的优化,为register提供了一种比反射更快速的方案,也就是对应源码中的private List findUsingInfo(Class
看完官方文档介绍,对eventbus的使用基本上就没什么问题了,再加上看了3天的源码解析,对eventbus的内部结构总算是有了一个大概的了解,如果有不对的地方,欢迎指正,另外对eventbus源码解析有高见的,也欢迎留言交流