【開源庫推薦】#3 Android EventBus的使用

one發表於2021-11-17

原文地址:【開源庫推薦】#3 Android EventBus的使用 | Stars-One的雜貨小窩

EventBus的Github

Event bus for Android and Java that simplifies communication between Activities, Fragments, Threads, Services, etc. Less code, better quality

Android和Java的事件匯流排,簡化了活動,片段,執行緒,服務等之間的通訊。程式碼越少,質量越好

EventBus是一款事件分發框架,可以跨程式,跨Activity/Fragment進行通訊,今天來簡單的來入下門

介紹

EventBus可以做什麼?

這裡來個例子比較好說明,我們知道Android中有個廣播機制,可以讓Activity和Service互相通訊,但是寫法過於麻煩,且不夠靈活;

又比如,一個Activity中含有幾個Fragment,其中的Fragment互相又要實現傳資料通訊,同時,也要與外層的Activity進行資料的互動,按照常規套路,我們使用傳參,寫法十分複雜

這個時候,我們就可以使用EventBus,就可以十分快速且簡單地實現我們需要實現的效果

本質上,EventBus也是使用了觀察者模式來實現其的功能

基本使用

1.繫結Activity

首先,匯入依賴

implementation 'org.greenrobot:eventbus:3.0.0'
  • 需要在Activity中的onCreate()方法中,與當前Activity繫結
  • 在Activity的onDestroy()方法中,進行解綁,否則會造成記憶體洩漏問題
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_event_bus)
    //繫結
    EventBus.getDefault().register(this)
}

override fun onDestroy() {
    super.onDestroy()
    //取消繫結
    EventBus.getDefault().unregister(this)
}

Activity的介面比較簡單,就是一個TextViewFrameLayout,之後建立一個Fragment放入FrameLayout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".EventBusActivity">
    <TextView
        android:id="@+id/tvContent"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textSize="20sp"
        android:text="Hello world" />
    <FrameLayout
        android:id="@+id/framelayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

2.宣告入口方法

在當前的繫結的Activity中宣告一個public的方法,返回值為void,同時,使用EventBus的註解@Subscribe對方法進行標識

注:此註解是3.0.0版本以後才加的,且方法一定是要公共的,否則EventBus會報錯,原因也是很簡單,估計EventBus是通過註解去找到方法,之後利用Java的反射特性進行回撥

@Subscribe(threadMode = ThreadMode.MAIN)
public fun changeText(str:String){
    tvContent.text = str
}

threadMode有四種模式:

  • POSTING(預設):如果使用事件處理函式指定了執行緒模型為POSTING,那麼該事件在哪個執行緒釋出出來的,事件處理函式就會在這個執行緒中執行,也就是說釋出事件和接收事件在同一個執行緒。線上程模型為POSTING的事件處理函式中儘量避免執行耗時操作,因為它會阻塞事件的傳遞,甚至有可能會引起應用程式無響應(ANR)。
  • MAIN:事件的處理會在UI執行緒中執行。事件處理時間不能太長,長了會ANR的。
  • BACKGROUND:如果事件是在UI執行緒中釋出出來的,那麼該事件處理函式就會在新的執行緒中執行,如果事件本來就是子執行緒中釋出出來的,那麼該事件處理函式直接在釋出事件的執行緒中執行。在此事件處理函式中禁止進行UI更新操作。
  • ASYNC:無論事件在哪個執行緒釋出,該事件處理函式都會在新建的子執行緒中執行,同樣,此事件處理函式中禁止進行UI更新操作。

這裡我們選用Main.且為了簡單起見,方法定義一個String型別,之後把activity中的文字修改為傳過來的資料

這個方法其實就是事件的接收者,之後在其他地方(如Fragment,Service或其他Activity)發出事件,EventBus會根據引數型別尋找對應的入口,同時將資料傳到當前的入口,我將其稱為入口方法

方法型別可以隨意定義,一般是某個事件定義個類用來儲存傳過來的資料,規範一點的話,可以統一下事件類中的格式,使用列舉來區分不同事件(當然,這種就比較適合那種只有一個入口)

3.post()方法發事件

之後我們在其他呼叫post方法發出事件即可,這裡給大家演示下載Fragment中的按鈕發出事件

Activity中設定Fragment

Fragment按鈕點選事件設定

btnChangeText.setOnClickListener {
	EventBus.getDefault().post("修改過後的文字")
}

之後即可實現點選按鈕實現改變文字的效果,如下圖

補充-postSticky()方法

上述中,使用的post()方法,但是可以看到程式碼提示中還存在一個postSticky()方法,這個方法是由什麼區別呢?

postSticky()是對應的粘性事件,我們可以看到Subscribe註解中存在一個sticky屬性,其預設是false

看到這就可以猜測到了,這兩者是配合使用的

那麼什麼是粘性事件呢?

比如說你發出了一個事件,但是由於對應的事件消費的Activity或Fragment物件還沒有被建立,於是你發出的事件就會被丟棄了

為了避免這種情況,EventBus提供了粘性事件,它會把事件先存在佇列中,等待Activity或Fragment啟動,則會自動把事件分發過去

postSticky()的使用與post()一樣,這裡不再贅述

外掛推薦

由於使用了EventBus,排查程式碼的時候非常不好排查,這裡推薦大家一款Android Studio的外掛,可以快速跳轉到對應的入口方法或是發出方法的程式碼

名字為EventBus3-IDEA

安裝之後,你就可以看見旁邊會有個小圖示,點選之後會跳轉到對應的程式碼

不過測試的時候感覺對Kotlin語言還沒適配,點選沒法跳轉,等作者等後續適配...

參考