事件總線是一個項目開發中必不可少的能力,市面上也有幾個很是有名的事件庫,好比 EventBus 以及基於 RxJava 的 RxBus 等java
可是他們在使用的時候都必需要手動註冊/反註冊監聽,咱們可否實現一個不須要手動反註冊的事件總線呢,換句話說,咱們如何實現一個可以在生命週期 destroy 的時候自定解綁監聽的事件總線呢android
首先簡單構思一下咱們的 EventBus —— 任意對象均可以做爲事件被髮送,經過對象的 Class 類型來對事件進行訂閱和分發git
咱們先定義一下 LifecycleEventBus
的幾個基礎方法(暫不考慮生命週期感知能力)github
object LifecycleEventBus {
// 添加監聽
fun <T : Any> observe(eventType: Class<T>, observer: EventObserver<T>) {}
// 移除監聽
fun <T : Any> removeObserver(observer: EventObserver<T>) {}
// 發送事件
fun <T: Any> sendEvent(event: T) {}
}
複製代碼
抽象的監聽者接口 —— EventObserver
markdown
interface EventObserver<T : Any> {
// 收到事件的時候回調函數,業務方在這裏實現對事件的處理邏輯
fun onEvent(event: T)
}
複製代碼
這樣一個簡易的 EventBus 就搭建好了,核心思路是:以事件的 Class 類型做爲 key,對應的 Observer 做爲 value,將此 key-value 存儲起來,在發送事件的時候,根據傳入的 event 的 Class 類型,找到對應的 Observer 而後調用其 onEvent()
方法來分發事件,實現代碼以下:app
private val observerMap =
mutableMapOf<Class<*>, MutableList<EventObserver<*>>>()
private fun addObserver(eventType: Class<*>, observer: EventObserver<*>) {
val observers = observerMap[eventType] ?: MutableList()
if (observerMap[eventType] == null) {
observerMap[eventType] = observers
}
if (!observers.contains(observer)) {
observers.add(observer)
}
}
fun <T: Any> sendEvent(event: T) {
val eventType = event::class.java
observerMap[eventType]?.forEach { observer ->
observer.onEvent(event)
}
}
複製代碼
藉助 androidx-lifecycle
中的 LifecycleEventObserver
咱們可讓 EventObserver
具有生命週期感知能力ide
若是對 LifecycleEventObserver
還比較陌生的同窗,能夠看看個人另外一篇文章《自定義生命週期以及實現生命週期感知能力 》函數
爲了兼容無生命週期的組件,咱們同時也要保留非生命週期感知能力的 Observer,爲此,咱們能夠抽象一個 Observer 包裝器 —— ObserverWrapper
oop
open class ObserverWrapper(val observer: EventObserver<*>) {
// 用於解綁生命週期,後續介紹
open fun detachObserver() {}
}
複製代碼
實現一個生命週期感知能力的 Observer —— LifecycleBoundObserver
post
private class LifecycleBoundObserver(
private val owner: LifecycleOwner,
observer: EventObserver<*>
) : ObserverWrapper(observer), LifecycleEventObserver {
init {
// 監聽生命週期的變化
owner.lifecycle.addObserver(this)
}
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
val currentState: Lifecycle.State = source.lifecycle.currentState
// 當生命週期即將銷燬的時候,移除監聽器
if (currentState == Lifecycle.State.DESTROYED) {
removeObserver(observer)
return
}
}
// 在移除監聽 removeObserver 中回調被移除的 observer 的
// detachObserver 方法來解綁對生命週期的監聽
override fun detachObserver() {
super.detachObserver()
owner.lifecycle.removeObserver(this)
}
}
複製代碼
而後添加監聽的地方修改以下:
// 因爲咱們使用了包裝類 ObserverWrapper,可是對於外部而言該包裝類是不可見的,爲了可以
// 正常移除 observer,咱們須要創建原始 observer 和 ObserverWrapper 的映射關係
// 這裏表現爲一個 HashMap
private val observerMap =
mutableMapOf<Class<*>, ConcurrentHashMap<EventObserver<*>, ObserverWrapper>>()
private fun addObserver(eventType: Class<*>, observerWrapper: ObserverWrapper) {
val observers = observerMap[eventType] ?: ConcurrentHashMap()
if (observerMap[eventType] == null) {
observerMap[eventType] = observers
}
observers.putIfAbsent(observerWrapper.observer, observerWrapper)
}
複製代碼
同時在移除監聽器的時候也要把對生命週期的監聽移除:
fun <T : Any> removeObserver(observer: EventObserver<T>) {
observerMap.forEach { (_, observers) ->
val wrapper = observers.remove(observer)
// 移除監聽的時候,同時也須要移除 lifecycle 的監聽
wrapper?.detachObserver()
}
}
複製代碼
如此,咱們就實現了一個具有生命週期感知能力的 Observer,在使用的時候傳入對應的 LifecycleOwner
就可實現自動解綁監聽
LifecycleEventBus.observe(lifecycleOwner, MyEvent::class.java, observer)
複製代碼
而對於不須要生命週期感知能力的 Observer,咱們直接使用 ObserverWrapper
就能夠了,代碼很簡單,這裏再也不贅述
當前的實現 observer 將運行在 sendEvent()
所在的線程,不少時候,咱們可能在子線程發送事件,可是指望在主線程監聽,那麼咱們就須要實現線程切換能力,讓 Observer 能夠運行在指定的線程上
定義 Enum 線程模式 —— ThreadMode
/** * ORIGIN: Observer 將運行在發送事件所在的線程 * MAIN: Observer 將運行在主線程 */
enum class ThreadMode {ORIGIN, MAIN}
複製代碼
給 observe()
方法增長參數,默認是 ThreadMode.ORIGIN
fun <T : EVENT> observe( owner: LifecycleOwner, eventType: Class<T>, observer: EventObserver<T>, threadMode: ThreadMode = ThreadMode.ORIGIN ) {
addObserver(eventType, LifecycleBoundObserver(owner, observer, threadMode))
}
複製代碼
把 threadMode
傳遞到 observer
中,當分發事件的時候,判斷若是 threadMode
爲 ThreadMode.MAIN
切換到主線程便可
if (threadMode == ThreadMode.MAIN) {
ThreadManager.runOnMainThread {
onEvent(it)
}
} else {
onEvent(it)
}
複製代碼
object ThreadManager {
private val mainHandler by lazy {
Handler(Looper.getMainLooper())
}
fun runOnMainThread(block: () -> Unit) {
if (isMainThread()) {
block()
} else {
mainHandler.post(block)
}
}
private fun isMainThread(): Boolean {
return Looper.myLooper() == Looper.getMainLooper()
}
}
複製代碼
至此,一個完整的具有生命週期感知能力的 EventBus 就完成了,總體代碼 100 左右,十分精簡。源碼詳情請到 GitHub 自行查看:LifecycleEventBus
相比 EventBus/RxBus 優點:
// difine an event
data class LoginEvent(val userId: String)
// define an observer
val observer = object : EventObserver<LoginEvent> {
override fun onEvent(event: LoginEvent) {
println("onEvent --> $event")
}
}
// add observer with lifecycleOwner.
// the observer will be removed when lifecycle goes to destroy
LifecycleEventBus.observe(this, LoginEvent::class.java, observer)
// send event
LifecycleEventBus.sendEvent(LoginEvent("12345"))
複製代碼