在 深入理解EventBus - 基本使用 已经初步了解了EventBus如何使用,下面从Thread Mode、Sticky Event、EventBus单例模式创建等方面,深入了解EventBus的使用,以满足各种场景的使用。
在 深入理解EventBus - 基本使用中,我们获取EventBus单例对象是通过EventBus.getDefault()方法。此时,EventBus对象的设置都是默认的。当然,大部分情况都是可以满足。都说小概率事件年年有。假如分发的事件,没有订阅者时,之前说过,会报异常。若不想报异常,让EventBus保持静默,不做扫描,该如何处理呢?那就不得不说EventBuilder,这个通过Builder模式创建EventBus对象了。下面先看EventBuilder常用的方法
EventBus build():基于当前EventBus配置创建EventBus
EventBus installDefaultEventBus():创建默认的EventBus对象,相当于EventBus.getDefault()。
EventBuilder addIndex(SubscriberInfoIndex index): 添加由EventBus“注释预处理器生成的索引
EventBuilder eventInheritance(boolean eventInheritance):默认情况下,EventBus认为事件类有层次结构(订户超类将被通知)
EventBuilder executorService(java.util.concurrent.ExecutorService executorService):定义一个线程池用于处理后台线程和异步线程分发事件
EventBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex):强制使用事件反射,即使事件已被设置索引
EventBuilder logNoSubscriberMessages(boolean logNoSubscriberMessages):打印没有订阅消息,默认为true
EventBuilder logSubscriberExceptions(boolean logSubscriberExceptions):打印订阅异常,默认true
EventBuilder sendNoSubscriberEvent(boolean sendNoSubscriberEvent):设置发送的的事件在没有订阅者的情况时,EventBus是否保持静默,默认true
EventBuilder sendSubscriberExceptionEvent(boolean sendSubscriberExceptionEvent):发送分发事件的异常,默认true
EventBuilder skipMethodVerificationFor(java.lang.Class<?> clazz) 在3.0以前,接收处理事件的方法名以onEvent开头,方法名称验证避免不是以此开头。
使用此方法用以排除用户类
EventBuilder strictMethodVerification(boolean strictMethodVerification) 启用严格的方法验证(默认:false)
EventBuilder throwSubscriberException(boolean throwSubscriberException) 如果onEvent***方法出现异常,是否将此异常分发给订阅者(默认:false)
根据EventBuilder的API,我们可以根据使用情况,创建我们所需要的EventBus对象了。从官方文档上,看了下面的两个例子。当然,你也可以自己写两个。
EventBus eventBus = EventBus.builder()
.logNoSubscriberMessages(false)
.sendNoSubscriberEvent(false).build();
2.EventBus捕获来自的onEvent方法抛出的异常,并发送订户例外事件可以但不必被处理
EventBus eventBus = EventBus.builder().throwSubscriberException(true).build();
<span style="font-size:14px;">public enum ThreadMode {
POSTING,
MAIN,
BACKGROUND,
ASYNC
}</span>
看上面的ThreadMode源码可以看出来,ThreadMode实际上就是一个枚举类型,定义了POSTING 、MAIN 、BACKGROUND、ASYNC等几个常量。这几个常量,在EventBus整个框架,到底起什么作用呢?下面我们一一解析:
事件的处理在和事件的发送在相同的进程,所以事件处理时间不应太长,不然影响事件的发送线程,而这个线程可能是UI线程.
@Subscribe(threadMode = ThreadMode.POSTING)
public void onMessage(MessageEvent event) {
log(event.message);
}
事件的处理会在UI线程中执行,事件处理不应太长时间
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(MessageEvent event) {
textField.setText(event.message);
}
事件的处理会在一个后台线程中执行,尽管是在后台线程中运行,事件处理时间不应太长。如果事件分发在主线程,件会被加到一个队列中,由一个线程依次处理这些事件,如果某个事件处理时间太长,会阻塞后面的事件的派发或处理。如果事件分发在后台线程,事件会立即执行处理。
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessage(MessageEvent event){
saveToDisk(event.message);
}
事件处理会在单独的线程中执行,主要用于在后台线程中执行耗时操作,每个事件会开启一个线程(有线程池),但最好限制线程的数目。
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessage(MessageEvent event){
backend.send(event.message);
}
EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));
2. 创建新的Activity,并在Activity中注册EventBus,订阅已分发的粘性事件
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@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();
}
MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class);
// 判断此粘性事件是否存在
if(stickyEvent != null) {
// 若粘性事件存在,将其删除
EventBus.getDefault().removeStickyEvent(stickyEvent);
}
查看EventBus API,可以看到removeStickyEvent(java.lang.Class<T> eventType)的返回值是<T> T,此方法的解释是删除并获取当前的粘性事件。所以上述示例,可以修改成:
MessageEvent stickyEvent = EventBus.getDefault().removeStickyEvent(MessageEvent.class);
// Better check that an event was actually posted before
if(stickyEvent != null) {
// Now do something with it
}
@Subscribe(priority = 100)
public void onEvent(MessageEvent event) {
…
// 取消分发的事件
EventBus.getDefault().cancelEventDelivery(event) ;
}
buildscript {
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
compile 'org.greenrobot:eventbus:3.0.0'
apt 'org.greenrobot:eventbus-annotation-processor:3.0.1'
}
apt {
arguments {
eventBusIndex "com.example.myapp.MyEventBusIndex"
}
}
2.使用索引(自定义)
/** This class is generated by EventBus, do not edit. */
public class MyEventBusIndex implements SubscriberInfoIndex {
private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;
static {
SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();
putIndex(new SimpleSubscriberInfo(com.whoislcj.testhttp.MainActivity.class, true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onDataSynEvent", com.whoislcj.testhttp.eventBus.DataSynEvent.class,
ThreadMode.MAIN, 100, false),
new SubscriberMethodInfo("onDataSynEvent1", com.whoislcj.testhttp.eventBus.TestEvent.class, ThreadMode.MAIN,
0, true),
}));
}
private static void putIndex(SubscriberInfo info) {
SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
}
@Override
public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
if (info != null) {
return info;
} else {
return null;
}
}
}
3.将索引添加至EventBus单例中
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
-keepattributes *Annotation*
-keepclassmembers class ** {
@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
<init>(java.lang.Throwable);
}
到此为止,EventBus的使用基本上算完成了,相信你一定会开启美妙的Android通信旅程,再也不用为繁琐的回调而烦恼了,再也不用Activity和Fragment之间的通信烦恼了。有兴趣看EventBus源码的童鞋,可以跟随鸿洋大神的脚步 Android EventBus源码解析 带你深入理解EventBus 。
参考资料:
1.Android EventBus源码解析 带你深入理解EventBus
2.官方文档