EventBus 簡介與實踐

本文基于EvnetBus 3.1.1 文中監(jiān)聽訂閱同義 Android開發(fā)角度 kotlin

EventBus是什么

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>) 

onReceiveEvent1onReceiveEvent2都會接收到前面兩次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結合的使用方法前方,結合實際自行選擇,感謝閱讀

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末苗傅,一起剝皮案震驚了整個濱河市班巩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌逊桦,老刑警劉巖抑进,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異匿情,居然都是意外死亡,警方通過查閱死者的電腦和手機炬称,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門玲躯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人府蔗,你說我怎么就攤上這事汞窗。” “怎么了不铆?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵裹唆,是天一觀的道長。 經常有香客問我许帐,道長,這世上最難降的妖魔是什么距芬? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任循帐,我火速辦了婚禮,結果婚禮上离斩,老公的妹妹穿的比我還像新娘。我一直安慰自己跛梗,他們只是感情好柿顶,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著宪祥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蝗羊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天翔悠,我揣著相機與錄音野芒,去河邊找鬼。 笑死撮抓,一個胖子當著我的面吹牛摇锋,可吹牛的內容都是我干的。 我是一名探鬼主播荸恕,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼融求,長吁一口氣:“原來是場噩夢啊……” “哼呕诉!你這毒婦竟也來了填渠?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤七芭,失蹤者是張志新(化名)和其女友劉穎蔑赘,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體耙箍,經...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡酥馍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年旨袒,在試婚紗的時候發(fā)現(xiàn)自己被綠了术辐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片施无。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖瑞躺,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情幢哨,我是刑警寧澤嫂便,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響几迄,放射性物質發(fā)生泄漏。R本人自食惡果不足惜木羹,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一解孙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧脐瑰,春花似錦、人聲如沸苍在。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽初肉。三九已至饰躲,卻和暖如春牙咏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背躬翁。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工盯拱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宁舰。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓奢浑,卻偏偏與公主長得像,于是被迫代替她去往敵國和親雀彼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內容

  • EventBus源碼分析(一) EventBus官方介紹為一個為Android系統(tǒng)優(yōu)化的事件訂閱總線,它不僅可以很...
    蕉下孤客閱讀 4,008評論 4 42
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,129評論 25 707
  • EventBus是一個 發(fā)布/訂閱 模式的消息總線庫著蟹,它簡化了應用程序內各組件間梢莽、組件與后臺線程間的通信,解耦了事...
    hanpfei閱讀 4,051評論 0 50
  • 終于在候機的時候涮雷,吃上了這一口轻局,又酸又辣份殿,那叫一個字:“酸爽嗽交!” 據說,酸辣粉的來歷是有典故的拾枣。 ...
    丫頭利貞閱讀 442評論 0 1
  • 《來自星星的你》講述了一個集千里眼順風耳任意門葫蘆七兄弟機器貓屬性于一身的帥哥,來到人世四百年俊啼,只對來到地球認識的...
    十點半的牛奶閱讀 2,034評論 2 6