本文基于EvnetBus 3.1.1 文中監(jiān)聽
和訂閱
同義 Android開發(fā)角度 kotlin
EventBus是什么
eventBus顧名思義就是事件總線
,實際上就是一個 事件發(fā)布者
/事件監(jiān)聽者(訂閱者)
的框架, 發(fā)布者發(fā)布Event偎肃,Bus自動處理與分發(fā),監(jiān)聽者被動的接受累颂。
在加入了這個框架后,我們需要做的非常簡單,只需要發(fā)送時間,然后在需要的地方接受就可以了,不需要關注這兩者是如何建立聯(lián)系的,從而快速穩(wěn)定地實現(xiàn)不同地方不同線程信息傳遞,極大簡化異步
和各種跳轉
時的通信凛俱。
EventBus的優(yōu)勢(官方):
- 簡化了組件之間的通信
- 事件發(fā)送者和接收者的解耦
- 很好地工作在Activities, Fragments,后臺線程中
- 避免復雜且容易出錯的依賴關系和生命周期問題
- 使代碼更簡單
- 很快(EventBus 3.x 版本性能非常好,官方自稱是同類框架中最快的)
- 很小(~50 K)
- 在實踐中被一億多安裝的應用程序所證明
- 具有高級特性,如線程分發(fā)瘦棋、訂閱者優(yōu)先級等
如何使用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的事件分發(fā)由"event"的類型event.getClass()
決定發(fā)給那個接收者的。封裝成EventMessage<T>的形式团甲,但EventBus并不會區(qū)分泛型
//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將吞下這次異常不會崩潰(有l(wèi)ogcat打悠ダ濉)脐区,可以通過event.code 或者類型判斷解決.既然這么封裝了,實際中肯定是用code來區(qū)分的
@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
三個訂閱者,無論其在代碼中的順序如何哩罪,執(zhí)行順序就是fun1
fun2
fun3
,這條結論并未從源碼驗證 -
注釋
@Subscribe
標明這是一個EventBus的訂閱者
說明一下 @Subscribe 注釋的參數,三個參數全部為可選-
threadMode
默認為ThreadMode.POSTING
-
POSTING
哪個線程發(fā)送际插,監(jiān)聽方法直接同線程被調用框弛,事件傳遞開銷最少捕捂,事件處理程序必須快速返回,否則可能導致主線程阻塞 -
MAIN
顯然將在Android的主線程執(zhí)行指攒。如果發(fā)布線程是主線程,監(jiān)聽方法直接執(zhí)行膝擂,否者將排隊等待(類似handle)隙弛,必須不能執(zhí)行耗時操作 -
MAIN_ORDERED
3.1.1
新加入的,執(zhí)行在主線程全闷,與MAIN
不同的是,一定會排隊執(zhí)行 -
BACKGROUND
如果事件發(fā)送在非主線程屏鳍,直接調用監(jiān)聽方法局服。在主線程的話,EventBus將在一個單一的后臺線程中排隊執(zhí)行降淮,同樣不應該執(zhí)行耗時任務搏讶,避免阻塞 -
ASYNC
將在單獨的線程中被調用并且總是獨立于發(fā)布線程和主線程,適合執(zhí)行耗時操作媒惕,EventBus使用一個線程池來有效地重用完成的異步任務,但依然應該避免同時觸發(fā)大量長時間運行的異步方法穿挨,以限制并發(fā)線程的數量
-
-
sticky
默認為false
sticky = true時,訂閱方法(參數類型為T
)會獲得最后一個被sticky發(fā)送的T
類型事件帽衙,即被"粘在緩存中"的每個類型中的最后一個,可用于頁面跳轉時傳送數據贞绵,可避免序列化 諸如TransactionTooLargeException之類 -
priority
默認為0,相同線程
中的監(jiān)聽者的執(zhí)行順序,數字越大越先榨崩,注意相同線程
!!!
-
注冊和取消注冊訂閱者
Android中,通常在生命周期中進行:
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
}
override fun onStop() {
super.onStop()
EventBus.getDefault().unregister(this)
}
4.發(fā)送事件
EventBus.getDefault().post(EventMessage(EventCode.EventPostTest, "coair"))
發(fā)送普通事件
EventBus.getDefault().postSticky(EventMessage(EventCode.EventPostTest,null))
發(fā)送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結合的使用方法前方,結合實際自行選擇,感謝閱讀