Android | 这是一份详细的 EventBus 使用教程

前言

  • Android开发中,EventBus事件总线机制十分常用;
  • 今天,我将整理EventBus详细的使用教程,追求简单易懂又不失深度,如果能帮上忙,请务必点赞加关注!

系列文章

延伸文章


目录


1. EventBus 机制简介

  • 定义
    一套 Android/Java 事件发布 / 订阅框架,由 greenrobot 团队开源
EventBus版本变更示意图
  • 作用
    在组件 / 线程间通信的应用场景中,将数据或事件传递给对应的订阅者,从而实现事件传递
EventBus原理示意图
  • 为什么要使用 EventBus ?
    在 Android 组件 / 线程间通信的应用场景中,EventBus 比传统的接口监听、Handler、Executors、LocalBroadcastManager更简洁可靠,具体描述如下:
示意图
  • 总结
    使用EventBus框架的原因:
    • 使用事件总线框架,实现事件发布者与订阅者松耦合
    • 提供了透明线程间通信,隐藏了发布线程与订阅线程间的线程切换

2. 相关概念

关于EventBus机制的相关概念如下:

EventBus相关概念示意图

3. 使用步骤

3.1 步骤1:添加依赖

  • 在module级build.gradle中添加依赖:
dependencies {
    def eventbus_version = '3.2.0'
    implementation "org.greenrobot:eventbus:$eventbus_version"
}
  • 使用编译时索引时,还需要依赖注解处理工具纯Java项目和Kotlin使用的工具不同:
    • Java项目使用annotationProcessor工具
    • Kotlin项目使用kapt工具
// Java:
android {
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [ eventBusIndex : 'com.have.a.good.MyEventBusAppIndex' ]
            }
        }
    }
}
 
dependencies {
    def eventbus_version = '3.2.0'
    implementation "org.greenrobot:eventbus:$eventbus_version"
    annotationProcessor "org.greenrobot:eventbus-annotation-processor:$eventbus_version"
}
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt' // ensure kapt plugin is applied
 
dependencies {
    def eventbus_version = '3.2.0'
    implementation "org.greenrobot:eventbus:$eventbus_version"
    kapt "org.greenrobot:eventbus-annotation-processor:$eventbus_version"
}
 
kapt {
    arguments {
        arg('eventBusIndex', 'com.have.a.good.MyEventBusAppIndex')
    }
}

3.2 步骤2:准备订阅者

  • 订阅者需要实现订阅方法,并使用@Subscribe注解修饰,具体描述如下:
准备订阅者
  • 举例:
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(MessageEvent event) {
        Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
    }
    
  • 五种线程模式具体描述如下:
五种线程模式

3.3 步骤3:注册与注销

  • 在发布事件之前,需要先注册订阅者;在订阅者生命周期结束时,需要注销订阅者,具体描述如下:
注册与注销
  • 举例:
@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}
 
@Override
public void onStop() {
    EventBus.getDefault().unregister(this);
    super.onStop();
}

3.4 步骤4:发布事件

  • 调用EventBus#post(Object)发布普通事件
  • 调用EventBus#postSticky(Object)发布粘性事件
发布事件
  • 举例:
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
  • 粘性事件具体描述如下:
粘性事件
  • 举例:
// 1. 订阅
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {   
    textField.setText(event.message);
}
// 2. 发布
EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));
// 3. 获取粘性事件
MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class);
if(stickyEvent != null) {
    // 4. 移除粘性事件
    EventBus.getDefault().removeStickyEvent(stickyEvent);
    // do something.
}
// 5. 移除粘性事件
MessageEvent stickyEvent = EventBus.getDefault().removeStickyEvent(MessageEvent.class);
if(stickyEvent != null) {
    // do something.
}

4. 编译时索引

  • EventBus 3.x相较于EventBus 2.x最大的改良就是 编译时索引,注解生成器的源码可查看:EventBus 注解处理器源码,具体描述如下:
编译时索引
  • 为了生成编译时索引,首先需要在build.gradle中配置索引文件,例如:
kapt {
    arguments {
        arg('eventBusIndex', 'com.have.a.good.MyEventBusAppIndex')
    }
}
  • 编译时,注解处理器将解析@Subscribe注解修饰的方法,生成索引类MyEventBusAppIndex.java),在运行时构建时添加索引,例如:
EventBus eventBus = EventBus.builder()
    .addIndex(new MyEventBusAppIndex())
    .build();
  • 索引类配置只对当前module有效,因此需要在每个包含订阅者的modulebuild.gradle中添加索引类配置,例如:
// App module 
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt' // ensure kapt plugin is applied

kapt {
    arguments {
        arg('eventBusIndex', 'com.have.a.good.MyEventBusAppIndex')
    }
}

dependencies {
    ...
    kapt "org.greenrobot:eventbus-annotation-processor:3.2.0"
    implementation project(path: ':base')
}

// Lib module
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt' // ensure kapt plugin is applied

kapt {
    arguments {
        arg('eventBusIndex', 'com.have.a.good.MyEventBusLibIndex')
    }
}

dependencies {
    ...
    api 'org.greenrobot:eventbus:3.2.0'
    kapt "org.greenrobot:eventbus-annotation-processor:3.2.0"
    implementation project(path: ':base')
}

以上配置将生成两个索引类文件,MyEventBusAppIndex.java只包含App Module中的订阅者索引,而MyEventBusLibIndex.java只包含Lib Module中的订阅者索引。


5. 构建者模式

  • 构建者模式(Builder Pattern)可以说是开源库的标配了,EventBus自然也不例外;

  • EventBus类封装了所有的API,调用EventBus.getDefault()获得默认的EventBus实例;

  • EventBusBuilder类用于构建EventBus实例,具体如下:

      1. 异常处理配置
    配置项 描述 默认值
    logSubscriberExceptions 订阅函数执行有异常时,打印异常信息 true
    sendSubscriberExceptionEvent 订阅函数执行有异常时,发布SubscriberExceptionEvent事件 true
    throwSubscriberException 订阅函数执行有异常时,抛出SubscriberException false
    logNoSubscriberMessages 事件无匹配订阅函数时,打印信息 true
    sendNoSubscriberEvent 事件无匹配订阅函数时,发布NoSubscriberEvent true
      1. 注册者索引配置
    配置项 描述 默认值
    ignoreGeneratedIndex 忽略订阅者索引 false
    addIndex(SubscriberInfoIndex index) 添加订阅者索引
      1. 事件订阅配置
    配置项 描述 默认值
    eventInheritance 是否触发父类事件订阅函数 true
    executorService(ExecutorService executorService) 线程池 Executors#
    newCachedThreadPool()
    strictMethodVerification 是否严格验证订阅函数签名 true
    skipMethodVerificationFor(Class<?> clazz) 跳过方法签名验证

6. 混淆

-keepattributes *Annotation*
// keep住所有被Subscribe注解标注的方法
-keepclassmembers class * {
    @org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }

这里着重讲解一下注释部分,因为生成编译时索引是在代码混淆之前进行的,而代码混淆之后类名和方法名都不一样了,这样就会导致运行时找不到编译时索引中记录的方法名了,因而得keep住所有被@Subscribe注解标注的方法。

  • 如果使用了AsyncExecutor,还需要配置混淆规则:
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
    <init>(java.lang.Throwable);
}

7. 总结

  • 本文对EventBus的使用进行了全面讲解
  • 下面我将继续深入讲解 EventBus 源码分析,感兴趣的同学可以点个关注!

推荐阅读


2020 永远不要放弃希望,祝愿大家都能够平安健康!武汉加油!

推荐阅读更多精彩内容