EventBus 簡介與實踐
本文基於EvnetBus 3.1.1 文中 監聽
和 訂閱
同義 Android開發角度 kotlin
EventBus是什麼

EventBus
eventBus顧名思義就是 事件匯流排
,實際上就是一個 事件釋出者
/ 事件監聽者(訂閱者)
的框架, 釋出者釋出Event,Bus自動處理與分發,監聽者被動的接受。
在加入了這個框架後,我們需要做的非常簡單,只需要傳送時間,然後在需要的地方接受就可以了,不需要關注這兩者是如何建立聯絡的,從而快速穩定地實現不同地方不同執行緒資訊傳遞,極大簡化 非同步
和各種 跳轉
時的通訊。
EventBus的優勢(官方):
- 簡化了元件之間的通訊
- 事件傳送者和接收者的解耦
- 很好地工作在Activities, Fragments,後臺執行緒中
- 避免複雜且容易出錯的依賴關係和生命週期問題
- 使程式碼更簡單
- 很快(EventBus 3.x 版本效能非常好,官方自稱是同類框架中最快的)
- 很小(~50 K)
- 在實踐中被一億多安裝的應用程式所證明
- 具有高階特性,如執行緒分發、訂閱者優先順序等
如何使用EventBus
1.EventBus新增到專案中
Android專案當然是使用Gradle
implementation 'org.greenrobot:eventbus:3.1.1'
2.定義事件
該步驟可選,可以跳過該部分直接閱讀後面
專案實踐中的事件封裝:
/** * [code]是該事件的識別編號,[data]為傳輸的資料,預設為空 */ data class EventMessage<T>(val code: Int, val data: T? = null)
需要說明的是,EventBus的事件分發由"event"的型別 event.getClass()
決定發給那個接收者的。封裝成EventMessage<T>的形式,但EventBus並不會區分泛型
//EventCode是自定義的一系列const Int值 fun xxx(){ EventBus.getDefault().post(EventMessage(EventCode.EventPostTest, "12345")) EventBus.getDefault().post(EventMessage(EventCode.EventPostTest2, 123)) } @Subscribe(threadMode = ThreadMode.MAIN) fun onReceiveEvent1(event: EventMessage<String>) @Subscribe(threadMode = ThreadMode.MAIN) fun onReceiveEvent2(event: EventMessage<Int>)
onReceiveEvent1
和 onReceiveEvent2
都會接收到前面兩次post事件,也不會自動轉型,EventBus將吞下這次異常不會崩潰(有logcat列印),可以通過event.code 或者型別判斷解決.既然這麼封裝了,實際中肯定是用code來區分的
@Subscribe(threadMode = ThreadMode.MAIN) fun onReceiveEvent1(event: EventMessage<String>) { if (event.data is String) { LogUtils.e(event.data + " String 的接收者") } } @Subscribe(threadMode = ThreadMode.MAIN) fun onReceiveEvent2(event: EventMessage<Int>) { if (event.code == EventCode.EventPostTest2) { LogUtils.e("${event.data} Int 的接收者") } }
3.準備訂閱者
宣告並用註釋標明一個訂閱方法
@Subscribe(threadMode = ThreadMode.MAIN) fun onReceiveEvent2(event: EventMessage<Int>) { if (event.code == EventCode.EventPostTest2) { LogUtils.e("${event.data} Int 的接收者") } }
-
引數
非常重要,決定收到什麼樣的事件 -
方法名
是隨意的,但根據多次實驗假設你有fun1
fun2
fun3
三個訂閱者,無論其在程式碼中的順序如何,執行順序就是fun1
fun2
fun3
,這條結論並未從原始碼驗證 -
註釋
@Subscribe
標明這是一個EventBus的訂閱者
說明一下 @Subscribe 註釋的引數,三個引數全部為可選-
threadMode
預設為ThreadMode.POSTING
-
POSTING
哪個執行緒傳送,監聽方法直接同線程被呼叫,事件傳遞開銷最少,事件處理程式必須快速返回,否則可能導致主執行緒阻塞 -
MAIN
顯然將在Android的主執行緒執行。如果釋出執行緒是主執行緒,監聽方法直接執行,否者將排隊等待(類似handle),必須不能執行耗時操作 -
MAIN_ORDERED
3.1.1
新加入的,執行在主執行緒,與MAIN
不同的是,一定會排隊執行 -
BACKGROUND
如果事件傳送在非主執行緒,直接呼叫監聽方法。在主執行緒的話,EventBus將在一個單一的後臺執行緒中排隊執行,同樣不應該執行耗時任務,避免阻塞 -
ASYNC
將在單獨的執行緒中被呼叫並且總是獨立於釋出執行緒和主執行緒,適合執行耗時操作,EventBus使用一個執行緒池來有效地重用完成的非同步任務,但依然應該避免同時觸發大量長時間執行的非同步方法,以限制併發執行緒的數量
-
-
sticky
預設為false
sticky = true時,訂閱方法(引數型別為T
)會獲得最後一個被sticky傳送的T
型別事件,即被"粘在快取中"的每個型別中的最後一個,可用於頁面跳轉時傳送資料,可避免序列化 諸如TransactionTooLargeException之類 -
priority
預設為0,相同執行緒
中的監聽者的執行順序,數字越大越先,注意相同執行緒
!!!
-
註冊和取消註冊訂閱者
Android中,通常在生命週期中進行:
override fun onStart() { super.onStart() EventBus.getDefault().register(this) } override fun onStop() { super.onStop() EventBus.getDefault().unregister(this) }
4.傳送事件
EventBus.getDefault().post(EventMessage(EventCode.EventPostTest, "coair"))
傳送普通事件
EventBus.getDefault().postSticky(EventMessage(EventCode.EventPostTest,null))
傳送sticky事件,最後一個該型別的事件將"粘"在快取中,以待相應訂閱者獲取,可重複獲取
實踐封裝
直接點,為了減少行數 刪了註釋
object MyBus { fun register(subscriber: Any) { val eventBus = EventBus.getDefault() if (!eventBus.isRegistered(subscriber)) { eventBus.register(subscriber) } } fun unregister(subscriber: Any) { val eventBus = EventBus.getDefault() if (eventBus.isRegistered(subscriber)) { eventBus.unregister(subscriber) } } fun post(event: EventMessage<*>) { EventBus.getDefault().post(event) } fun postSticky(event: EventMessage<*>) { EventBus.getDefault().postSticky(event) } } data class EventMessage<T>(val code: Int, val data: T? = null) fun <T> Int.todo(event: EventMessage<T>, t: (T?) -> Unit) { if (event.code == this) { t(event.data) } } abstract class BaseActivity : AppCompatActivity() { override fun onStart() { super.onStart() if (isRegisteredEventBus()) { MyBus.register(this) } } override fun onStop() { super.onStop() if (isRegisteredEventBus()) { MyBus.unregister(this) } } open fun isRegisteredEventBus() = false open val uiEvents: Map<Int, (Any?) -> Unit> = mapOf() @Subscribe(threadMode = ThreadMode.MAIN) fun onReceiveEvent(event: EventMessage<*>) { uiEvents.forEach { code, func -> code.todo(event) { func(it) } } } }
使用:這種封裝方式單純的更新UI還是挺方便的
class MainActivity : BaseBackActivity() { override fun isRegisteredEventBus() = true override val uiEvents = mapOf( EventCode.EventPostTest to ::justToast ) private fun justToast(s: Any?) =... }
結語
EventBus是個使用很簡單的庫,也有和RxAndroid結合的使用方法,結合實際自行選擇,感謝閱讀