EventBus是我们开发中比较常用的一个中间件,这里基于3.1.1版本进行源码剖析。
使用EventBus的步骤:
1.添加库依赖,添加配置;
implementation 'org.greenrobot:eventbus:3.1.1'
// 给EventBus配置索引,提升效率 使用annotationProcessor 属性将EventBus批注处理器添加到构建中
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1' // 可选
- 添加配置:(可选)
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
// 设置参数 eventBusIndex以指定要生成的索引的完全限定类
arguments = [ eventBusIndex : 'com.fly.kuanquan.EventBusIndex' ] // 这里要修改为你项目的包名
}
}
}
2.初始化
- 这里有个知识点,我们一般使用EventBus是这么写的:
EventBus.getDefault().register(this);
其实EventBus这个类的构造函数不是 private 而是 public,咋一看违背单例模式的写法,这是为什么呢?
原因就是,EventBus 可以创造出很多条总线来,不同的总线之间是不能传递事件的(不能通信)。
自定义创建EventBus:
EventBus eventBus = EventBus.builder()
.logNoSubscriberMessages(false)
.sendNoSubscriberEvent(false)
.build();
eventBus.register(this);
3.注销EventBus
这个没什么好说的就是把上面创建并注册好的EventBus注销掉
EventBus.getDefault().unregister(this);
// 或者
eventBus.unregister(this);
4.创建接收(订阅)事件的方法
@Subscribe(threadMode = ThreadMode.POSTING,sticky = false,priority = 4)
public void onEventThread(EventCenter eventCenter){
switch (eventCenter.getEventType()) {
case EventType.ONE:
Log.e("MainActivity", eventCenter.getEventType());
break;
default:
break;
}
// EventBus.getDefault().removeStickyEvent(eventCenter);
// EventBus.getDefault().cancelEventDelivery(eventCenter);
}
PS:
这里面涉及到的知识点,@Subscribe注解
- threadMode: 在EventBus中有四种线程模式
POSTING, // EventBus 默认的线程模式 就是订阅的线程和发送事件的线程为同一线程
MAIN, // 主线程,使用此模式的订阅必须快速返回,以避免阻塞主线程
MAIN_ORDERED, // 主线程,与 MAIN 不同,事件将始终排队等待传递。这样可以确保后调用不阻塞
ASYNC // 异步线程
sticky: sticky事件是事件订阅者(消费者)在事件发布之后再注册,依然能接收到该事件的特殊类型。详情我们在后面的源码中详细分析。
priority :优先级,默认为0,数值越大,优先级越高,越提前接收到事件。
如果在同一总线中,接受的线程模式为POSTING,这时候在优先级高的订阅者中接收并取消该事件,优先级底的就接收不到该事件了。
注:优先级不会影响具有不同ThreadModes的订阅者的传递顺序
- 取消事件传递:
@Subscribe(threadMode = ThreadMode.POSTING,sticky = false,priority = 4)
public void onEventThread(EventCenter eventCenter){
switch (eventCenter.getEventType()) {
case EventType.ONE:
Log.e("MainActivity", eventCenter.getEventType());
break;
default:
break;
}
// 取消事件传递 这里的参数是订阅的实体参数
EventBus.getDefault().cancelEventDelivery(eventCenter);
}
注:当优先级更高的想取消事件传递时,只有当threadMode = ThreadMode.POSTING处于此状态才能取消事件传递有效。
5.发送事件
// 发送 sticky 事件,先发送后注册也能接受到该事件
EventBus.getDefault().postSticky(new EventCenter<>(EventType.ONE));
// 普通发送事件
EventBus.getDefault().post(new EventCenter<>(EventType.ONE));
以上都是最基本的用法,下面我们说一种可以提升效率的用法。
为什么说提升效率呢,因为EventBus3.0以后都是基于注解反射实现的,大家都知道反射是效率很低的,所以为了提高效率新增了一种办法,配置索引。
- 使用annotationProcessor
就是上面在app builde中添加脚本配置:
defaultConfig {
.....
javaCompileOptions {
annotationProcessorOptions {
// 设置参数 eventBusIndex以指定要生成的索引的完全限定类
arguments = [ eventBusIndex : 'com.fly.kuanquan.EventBusIndex' ] // 这里要修改为你项目的包名
}
}
}
dependencies {
.....
// 给EventBus配置索引,提升效率 使用annotationProcessor 属性将EventBus批注处理器添加到构建中
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1'
// 配置完成后重新Rebuild Project项目,
// 然后我们到\app\build\generated\source\apt\debug\package\查看是否生成所配置的的文件EventBusIndex
}
下面是我demo中app下的完整build.gladle,大家可做参考:
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion '26.0.2'
defaultConfig {
applicationId "com.kuanquan.testdemo"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
javaCompileOptions {
annotationProcessorOptions {
// 设置参数 eventBusIndex以指定要生成的索引的完全限定类
arguments = [ eventBusIndex : 'com.fly.kuanquan.EventBusIndex' ] // 这里要修改为你项目的包名
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:design:25.0.1'
compile 'com.android.support.constraint:constraint-layout:1.1.2'
compile 'com.android.support:recyclerview-v7:25.+'
compile 'com.google.code.gson:gson:2.8.2'
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'com.squareup.retrofit2:retrofit:2.5.0'
compile 'com.squareup.okhttp3:okhttp:3.12.1'
//引入Gson支持
compile 'com.squareup.retrofit2:converter-gson:2.0.1'
// 给EventBus配置索引,提升效率 使用annotationProcessor 属性将EventBus批注处理器添加到构建中
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1'
// 配置完成后重新Rebuild Project项目,
// 然后我们到\app\build\generated\source\apt\debug\package\查看是否生成所配置的的文件EventBusIndex
}
PS:
配置完成后重新Rebuild Project项目,然后我们到\app\build\generated\source\apt\debug\package\查看是否生成所配置的的文件EventBusIndex。EventBusIndex名称可随意自定义
生成的索引:
package com.fly.kuanquan;
import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;
import org.greenrobot.eventbus.meta.SubscriberMethodInfo;
import org.greenrobot.eventbus.meta.SubscriberInfo;
import org.greenrobot.eventbus.meta.SubscriberInfoIndex;
import org.greenrobot.eventbus.ThreadMode;
import java.util.HashMap;
import java.util.Map;
/** This class is generated by EventBus, do not edit. */
public class EventBusIndex implements SubscriberInfoIndex {
private static final Map, SubscriberInfo> SUBSCRIBER_INDEX;
代码中设置了几种模式,这里就会生成几种
static {
SUBSCRIBER_INDEX = new HashMap, SubscriberInfo>();
putIndex(new SimpleSubscriberInfo(com.kuanquan.testdemo.FirstActivity.class, true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onEventThreadActivity", com.kuanquan.testdemo.EventCenter.class,
ThreadMode.POSTING, 1, false),
}));
putIndex(new SimpleSubscriberInfo(com.kuanquan.testdemo.MainActivity.class, true, new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onEventThread", com.kuanquan.testdemo.EventCenter.class, ThreadMode.MAIN),
}));
}
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;
}
}
}
索引的使用:
- 在Application中进行初始化
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
EventBus.builder().addIndex(new EventBusIndex()).installDefaultEventBus();
}
}
接下来注册、注销、订阅方法、发送事件和上面一样一样的。
注意:在第一次使用默认EventBus实例之前,这只能执行一次。对installDefaultEventBus()的后续调用 将引发异常。这可确保您的应用中的行为一致。所以应该在Application.class使用配置,和使用索引。
当然索引可以创建多个:
EventBus eventBus = EventBus.builder()
.addIndex(new EventBusAppIndex())
.addIndex(new EventBusIndex()).build();
前提:你的应用程序有很多library和一个app组成,这样把上面的配置在每个library中配置一遍,就可以生成多个索引,然后把多个索引在Application中如上配置就好了。
代码混淆
-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);
}
总结:
- EventBus在一个订阅者类中只能注册一次。否则会抛出异常。
- EventBus的Configuration配置和索引使用的时候注意installDefaultEventBus()只能调用一次。否则会抛出异常。
- 当EventBus无法使用索引时,它将在运行时自动回退到反射。因此它仍然可以工作,只是有点慢。所以添加索引可以让EventBus的使用效率更高。
- 事件的优先级中设置的值越大优先级越高,取消事件传递,必须是threadMode = ThreadMode.POSTING在这个情况下才能有效。
- EventBus可以创建很多条总线的,总线与总线之间是不能通讯的。相互独立的。
最后附上官网的图:
源码分析:https://www.jianshu.com/p/d521630da2c2
谢谢阅读,据说点赞的都是帅哥靓女!