通过上一篇文章《EventBus 3.0相见恨晚》对EventBus3.0的原理及使用方法有了简单了解。
下面就其原理和使用方法做更深入细致的了解。
EventBus is an open-source library for Android using the publisher/subscriber pattern for loose coupling
这句话是greenrobot官网对EventBus的解释。
EventBus是一个针对Android为了松耦合的基于事件发布/订阅模式(观察者模式)的开源库。
从上图我们可以看到EventBus的设计结构非常简单。
从之前对EventBus的Demo我们可以看到,使用EventBus的关键是订阅者方法的实现,也就是事件处理方法onMessageEvent的实现。这个方法,才是我们处理数据、实现UI更新的关键。
@Subscribe(threadMode = ThreadMode.POSTING,sticky = false,priority = 1)
public void onMessageEvent(MessageEvent event) {
tv.setText(event.message);
}
这里再强调一遍,这个订阅者方法一定要添加@Subscribe这个注解,这个注解的完整参数如上,后面是一些可选的参数。下面就各个参数做一下分析:
EventBus的ThreadMode总共有四种,并且都是在订阅者中的@Subscribe里进行制定的。下面就来看一下这四种ThreadMode。
我们之前的Demo就是这样,事件发送是在SecondActivity的主线程,那么onMessageEvent在默认情况下必然会在主线程执行。
还是之前的Demo,我们在SecondActivity中实现登录操作,正常情况下这必然是个网络请求,而这个网络请求必然不会在主线程(UI线程)中发生,所以,当我们完成网络请求发布事件的时候,发布事件所在的线程就不再是UI线程了,我们的onMessageEvent的ThreadMode就不能为默认值,必须指定为MAIN,确保其在主线程进行对UI的操作。
这种情况,一般是我们需要在订阅者方法中进行耗时的操作。
这里我们可以简单的测试一下,加深理解:
下面代码用4种不同的Thread模式订阅同一事件MessageEvent
@Subscribe(threadMode = ThreadMode.PostThread)
public void onMessageEventPostThread(MessageEvent messageEvent) {
Log.e("PostThread", Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.MainThread)
public void onMessageEventMainThread(MessageEvent messageEvent) {
Log.e("MainThread", Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.BackgroundThread)
public void onMessageEventBackgroundThread(MessageEvent messageEvent) {
Log.e("BackgroundThread", Thread.currentThread().getName());
}
@Subscribe(threadMode = ThreadMode.Async)
public void onMessageEventAsync(MessageEvent messageEvent) {
Log.e("Async", Thread.currentThread().getName());
}
Log.e("postEvent", Thread.currentThread().getName());
EventBus.getDefault().post(new MessageEvent());
看一下日志输出:
可以看出,在主线程发布事件,那么Post和Main 模式下,订阅者方法也是在主线程执行,其他两种模式下分别是独立的线程。
new Thread(new Runnable() {
@Override
public void run() {
Log.e("postEvent", Thread.currentThread().getName());
EventBus.getDefault().post(new MessageEvent());
}
}).start();
看一下日志输出:
子线程发布事件时,只有ThreadMode 为MAIN时,订阅者方法才会在主线程执行。其余都是在独立的线程。
这个单词sticky的意思是粘贴性,这里的意思就是在发送事件之后再订阅该事件也能收到该事件
默认为false。
这个priority的意义是优先级,这里主要说一下结论和注意事项
在性能方面,EventBus 3由于使用了注解,比起使用反射来遍历方法的2.4版本逊色不少。但开启索引后性能远远超出之前的版本。下面就来看一下对于EventBus的另一种使用方式。
在Project的build.gradle中添加如下代码:
buildscript {
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
然后在app的build.gradle中添加如下代码:
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"
}
}
重新rebuild之后会在build目录下面生成MyEventBusIndex文件,文件名可以自定义。下面就来看一下如何使用这个MyEventBusIndex.我们可以自定义设置自己的EventBus来为其添加MyEventBusIndex对象。代码如下所示:
EventBus eventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();
我们也能够将MyEventBusIndex对象安装在默认的EventBus对象当中。代码如下所示:
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
// Now the default instance uses the given index. Use it like this:
EventBus eventBus = EventBus.getDefault();
剩下对于EventBus的用法则是一模一样。当然也建议通过添加订阅者索引这种方式来使用EventBus,这样会比通过反射的方式来解析注解效率更高。
不使用EventBus的前提下,在Android内部各个组件的交互通信可以说是杂乱无章,各种接口定义,注册、回调。搞得整个代码有着很严重的耦合,接口中多一个参数,参数类型变化都会导致很多地方要改。
这种思路注定了随着项目越来越庞大,耦合会越发的严重,所以势必需要一种新的思路来解决这个问题。
而EventBus的出现,很好的解决了这个问题
从这两幅图,我们可以清晰的感受到,EventBus给我们代码整体的结构带来多么大的益处,单从图上就可以看到明显减少了各个组件之间的耦合;同时从代码角度出发,EventBus短短几行代码,就可以实现之前通过接口-注册接口-回调 等一系列的工作才能完成的工作量。
当然,凡事要好必然有坏,EventBus使用方式的简单,也会导致我们在出现问题时无从下手,这就需要长时间的积累经验了。