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

点赞关注,不再迷路,你的支持对我意义重大!

🔥 Hi,我是丑丑。本文 「Android 路线」| 导读 —— 从零到无穷大 已收录,这里有 Android 进阶成长路线笔记 & 博客,欢迎跟着彭丑丑一起成长。(联系方式在 GitHub)

前言

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

目录


前置知识

这篇文章的内容会涉及以下前置 / 相关知识,贴心的我都帮你准备好了,请享用~


1. EventBus 概述

  • 定义:一套 Android / Java 事件订阅 / 发布框架,由 greenrobot 团队开源。
  • 作用:在组件 / 线程间通信的场景中,将数据或事件传递给对应的订阅者。
  • 为什么要使用 EventBus (特点)?
    在 Android 组件 / 线程间通信的应用场景中,EventBus 比传统的接口监听、Handler、Executors、LocalBroadcastManager 更简洁可靠,具体描述如下:
    • 1、使用事件总线框架,实现事件发布者与订阅者松耦合
    • 2、提供了透明线程间通信,隐藏了发布线程与订阅线程间的线程切换
  • EventBus 相关概念
    关于EventBus机制的相关概念如下:

2. 使用步骤

在分析 EventBus 的使用原理之前,我们先来介绍下 EventBus 的使用步骤。

2.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')
    }
}

2.2 步骤2:准备订阅者

订阅者需要实现订阅方法,并使用@Subscribe注解修饰,具体要求如下:

举例:

@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
    Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}

@Subscribe 注解参数中,threadMode参数决定了使用的线程模型,目前一共有五种:

2.3 步骤3:注册与注销

在发布事件之前,需要先 注册订阅者。而在订阅者生命周期结束时,需要 注销订阅者

举例:

@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}
 
@Override
public void onStop() {
    EventBus.getDefault().unregister(this);
    super.onStop();
}

2.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.
}

3. 编译时索引

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 有效,因此需要在每个包含订阅者的 module 级build.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中的订阅者索引。


4. 构建者模式

构建者模式(Builder Pattern) 可以说是开源库的标配了,EventBus 也不例外。你可以使用EventBusBuilder来构建 EventBus 实例,也可以直接调用EventBus.getDefault()获得默认的 EventBus 实例;

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

5. 混淆

ProGuard 和它的继承者 R8 都提供了压缩、优化、混淆和预校验四大功能。压缩和优化会移除未使用的类/方法/字段,混淆会使用无意义的简短名称重命名类/方法/字段。

@Subscribe 订阅方法是通过反射调用的,在编译时没有直接调用,如果不增加反混淆规则的话,在运行时会出现找不到方法名的情况。因此,EventBus需要配置以下混淆规则:

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

如果使用了AsyncExecutor,还需要配置混淆规则:

-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
    <init>(java.lang.Throwable);
}

更多内容:《Android | 代码混淆到底做了什么?》


6. 总结

  • EventBus 是一套 Android / Java 事件订阅 / 发布框架,用于在组件 / 线程间通信的场景中将数据或事件传递给订阅者,EventBus 的特点是可以实现事件订阅者与发布者解耦,以及透明地线程切换;

  • EventBus 3.x 中,订阅者需要使用 @Subscribe 注解修饰订阅方法,可选五种线程模式(POSTING、MAIN、MAIN_ORDERED、BACKGROUND 和 ASYNC);

  • 编译时索引的原理是通过编译时注解处理器生成索引表,记录事件 —— 订阅关系的映射,在运行时直接加载索引表。如果不使用编译时索引,在注册订阅者时就需要递归反射查找类本身与父类中使用@Subscribe注解修饰的方法,影响性能;

  • @Subscribe 订阅方法是通过反射调用的,在编译时没有直接调用,如果不增加反混淆规则的话,在运行时会出现找不到方法名的情况。


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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266