Android | 這是一份詳細(xì)的 EventBus 使用教程

點(diǎn)贊關(guān)注,不再迷路,你的支持對(duì)我意義重大!

?? Hi,我是丑丑。本文 「Android 路線」| 導(dǎo)讀 —— 從零到無窮大 已收錄,這里有 Android 進(jìn)階成長(zhǎng)路線筆記 & 博客,歡迎跟著彭丑丑一起成長(zhǎng)。(聯(lián)系方式在 GitHub)

前言

  • 在 Android 開發(fā)中,EventBus 事件總線機(jī)制十分常用;
  • 今天,我將整理 EventBus 詳細(xì)的使用教程,追求簡(jiǎn)單易懂又不失深度。如果能幫上忙,請(qǐng)務(wù)必點(diǎn)贊加關(guān)注,這真的對(duì)我非常重要。

目錄


前置知識(shí)

這篇文章的內(nèi)容會(huì)涉及以下前置 / 相關(guān)知識(shí),貼心的我都幫你準(zhǔn)備好了,請(qǐng)享用~


1. EventBus 概述

  • 定義:一套 Android / Java 事件訂閱 / 發(fā)布框架,由 greenrobot 團(tuán)隊(duì)開源。
  • 作用:在組件 / 線程間通信的場(chǎng)景中,將數(shù)據(jù)或事件傳遞給對(duì)應(yīng)的訂閱者。
  • 為什么要使用 EventBus (特點(diǎn))?
    在 Android 組件 / 線程間通信的應(yīng)用場(chǎng)景中,EventBus 比傳統(tǒng)的接口監(jiān)聽、Handler、Executors、LocalBroadcastManager 更簡(jiǎn)潔可靠,具體描述如下:
    • 1、使用事件總線框架,實(shí)現(xiàn)事件發(fā)布者與訂閱者松耦合;
    • 2、提供了透明線程間通信,隱藏了發(fā)布線程與訂閱線程間的線程切換。
  • EventBus 相關(guān)概念
    關(guān)于EventBus機(jī)制的相關(guān)概念如下:

2. 使用步驟

在分析 EventBus 的使用原理之前,我們先來介紹下 EventBus 的使用步驟。

2.1 步驟1:添加依賴

  • 在 module 級(jí)build.gradle中添加依賴:
dependencies {
    def eventbus_version = '3.2.0'
    implementation "org.greenrobot:eventbus:$eventbus_version"
}
  • 使用編譯時(shí)索引時(shí),還需要依賴 注解處理工具,注意:純 Java 項(xiàng)目和 Kotlin 使用的注解處理工具不同:
    • Java 項(xiàng)目使用annotationProcessor
    • Kotlin 項(xiàng)目使用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:準(zhǔn)備訂閱者

訂閱者需要實(shí)現(xiàn)訂閱方法,并使用@Subscribe注解修飾,具體要求如下:

舉例:

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

@Subscribe 注解參數(shù)中,threadMode參數(shù)決定了使用的線程模型,目前一共有五種:

2.3 步驟3:注冊(cè)與注銷

在發(fā)布事件之前,需要先 注冊(cè)訂閱者。而在訂閱者生命周期結(jié)束時(shí),需要 注銷訂閱者。

舉例:

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

2.4 步驟4:發(fā)布事件

注冊(cè)訂閱者之后,就可以發(fā)布事件了,目前有兩種事件:

  • 調(diào)用EventBus#post(Object)發(fā)布普通事件
  • 調(diào)用EventBus#postSticky(Object)發(fā)布粘性事件
發(fā)布事件

舉例:

EventBus.getDefault().post(new MessageEvent("Hello everyone!"));

粘性事件 的特點(diǎn)如下:

舉例:

1、訂閱
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {   
    textField.setText(event.message);
}

2、發(fā)布
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. 編譯時(shí)索引

EventBus 3.x相較于EventBus 2.x最大的改良就是 編譯時(shí)索引,注解生成器的源碼可查看:EventBus 注解處理器源碼,具體描述如下:

為了生成編譯時(shí)索引,首先需要在build.gradle中配置索引文件,例如:

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

編譯時(shí),注解處理器 將解析@Subscribe注解修飾的方法,生成 索引類MyEventBusAppIndex.java。你需要做的是在運(yùn)行時(shí)構(gòu)建時(shí)添加索引,例如:

EventBus eventBus = EventBus.builder()
    .addIndex(new MyEventBusAppIndex())
    .build();

需要注意:索引類配置只對(duì)當(dāng)前 module 有效,因此需要在每個(gè)包含訂閱者的 module 級(jí)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')
}

以上配置將生成兩個(gè)索引類文件,MyEventBusAppIndex.java只包含App Module中的訂閱者索引,而MyEventBusLibIndex.java只包含Lib Module中的訂閱者索引。


4. 構(gòu)建者模式

構(gòu)建者模式(Builder Pattern) 可以說是開源庫(kù)的標(biāo)配了,EventBus 也不例外。你可以使用EventBusBuilder來構(gòu)建 EventBus 實(shí)例,也可以直接調(diào)用EventBus.getDefault()獲得默認(rèn)的 EventBus 實(shí)例;

  • 1、異常處理配置
配置項(xiàng) 描述 默認(rèn)值
logSubscriberExceptions 訂閱函數(shù)執(zhí)行有異常時(shí),打印異常信息 true
sendSubscriberExceptionEvent 訂閱函數(shù)執(zhí)行有異常時(shí),發(fā)布SubscriberExceptionEvent事件 true
throwSubscriberException 訂閱函數(shù)執(zhí)行有異常時(shí),拋出SubscriberException false
logNoSubscriberMessages 事件無匹配訂閱函數(shù)時(shí),打印信息 true
sendNoSubscriberEvent 事件無匹配訂閱函數(shù)時(shí),發(fā)布NoSubscriberEvent true
  • 2、索引配置
配置項(xiàng) 描述 默認(rèn)值
ignoreGeneratedIndex 忽略訂閱者索引 false
addIndex(SubscriberInfoIndex index) 添加訂閱者索引
  • 3、事件訂閱配置
配置項(xiàng) 描述 默認(rèn)值
eventInheritance 是否觸發(fā)父類事件訂閱函數(shù) true
executorService(ExecutorService executorService) 線程池 Executors#
newCachedThreadPool()
strictMethodVerification 是否嚴(yán)格驗(yàn)證訂閱函數(shù)簽名 true
skipMethodVerificationFor(Class<?> clazz) 跳過方法簽名驗(yàn)證

5. 混淆

ProGuard 和它的繼承者 R8 都提供了壓縮、優(yōu)化、混淆和預(yù)校驗(yàn)四大功能。壓縮和優(yōu)化會(huì)移除未使用的類/方法/字段,混淆會(huì)使用無意義的簡(jiǎn)短名稱重命名類/方法/字段。

@Subscribe 訂閱方法是通過反射調(diào)用的,在編譯時(shí)沒有直接調(diào)用,如果不增加反混淆規(guī)則的話,在運(yùn)行時(shí)會(huì)出現(xiàn)找不到方法名的情況。因此,EventBus需要配置以下混淆規(guī)則:

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

如果使用了AsyncExecutor,還需要配置混淆規(guī)則:

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

更多內(nèi)容:《Android | 代碼混淆到底做了什么?》


6. 總結(jié)

  • EventBus 是一套 Android / Java 事件訂閱 / 發(fā)布框架,用于在組件 / 線程間通信的場(chǎng)景中將數(shù)據(jù)或事件傳遞給訂閱者,EventBus 的特點(diǎn)是可以實(shí)現(xiàn)事件訂閱者與發(fā)布者解耦,以及透明地線程切換;

  • EventBus 3.x 中,訂閱者需要使用 @Subscribe 注解修飾訂閱方法,可選五種線程模式(POSTING、MAIN、MAIN_ORDERED、BACKGROUND 和 ASYNC);

  • 編譯時(shí)索引的原理是通過編譯時(shí)注解處理器生成索引表,記錄事件 —— 訂閱關(guān)系的映射,在運(yùn)行時(shí)直接加載索引表。如果不使用編譯時(shí)索引,在注冊(cè)訂閱者時(shí)就需要遞歸反射查找類本身與父類中使用@Subscribe注解修飾的方法,影響性能;

  • @Subscribe 訂閱方法是通過反射調(diào)用的,在編譯時(shí)沒有直接調(diào)用,如果不增加反混淆規(guī)則的話,在運(yùn)行時(shí)會(huì)出現(xiàn)找不到方法名的情況。


2020 永遠(yuǎn)不要放棄希望,祝愿大家都能夠平安健康!武漢加油!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容