Android App封装 —— 实现自己的EventBus

1,592 阅读2分钟

项目搭建经历记录

  1. Android App封装 ——架构(MVI + kotlin + Flow)
  2. Android App封装 —— ViewBinding
  3. Android App封装 —— DI框架 Hilt?Koin?
  4. Android App封装 —— 实现自己的EventBus

背景

在项目Github wanandroid中我们经常会遇到跨页面通信的需求,但传统的EventBus都有各自的缺点,如EventBus和RxBus需要自己管理生命周期,比较繁琐,基于LiveData的Bus切线程比较困难等。于是我参考了一些使用Flow实现EventBus的文章,结合自身需求,实现了极简的EventBus。

EventBus

image.png

EventBus是用于 Android 和 Java 的发布/订阅事件总线。Publisher可以将事件Event post给每一个订阅者Subscriber中接收,从而达到跨页面通信的需求。

可以看出EventBus本身就是一个生产者消费者模型,而在我们第一篇搭建MVI框架的时候,用到的Flow天然就支持生产者和消费者模型,所以我们可以自己用Flow搭建一个自己的EventBus

基于Flow搭建EventBus

根据EventBus的架构图,我们来用Flow搭建,需要定义一下几点

  1. 定义事件Event
  2. 发送者 Publisher 如何发送事件
  3. 如何存储Event并且分发
  4. 如何订阅事件

1. 定义事件

sealed class Event {
    data class ShowInit(val msg: String) : Event()
}

这个和之前搭建MVI框架类似,用一个sleaed classdata class或者object来定义事件,用来传递信息

2. 发送事件

fun post(event: Event, delay: Long = 0) {
        ...
}

发送事件定义一个这样的函数就可以了,传入事件和延迟时间

3. 存储Event并且分发

对于同一种Event,我们可以用一个SharedFlow来存储,依次发送给订阅方。而在整个App中,我们会用到各种不同种类的Event,所以这时候我们就需要用到HashMap去存储这些Event了。数据结构如下:

private val flowEvents = ConcurrentHashMap<String, MutableSharedFlow<Event>>()

4. 订阅事件

inline fun <reified T : Event> observe(
    lifecycleOwner: LifecycleOwner,
    minState: Lifecycle.State = Lifecycle.State.CREATED,
    dispatcher: CoroutineDispatcher = Dispatchers.Main,
    crossinline onReceived: (T) -> Unit
)
  • lifecycleOwner,用来定义订阅者的生命周期,这样我们就不需要额外管理注册与反注册了
  • minState,定义执行订阅的生命周期State
  • dispatcher,定义执行所在的线程
  • onReceived,收到Event后执行的Lamda

使用

    //任何地方
    FlowEventBus.post(Event.ShowInit("article init"))

    // Activity或者Fragment中
    FlowEventBus.observe<Event.ShowInit>(this, Lifecycle.State.STARTED) {
        binding.button.text = it.msg
    }

完整代码

object FlowEventBus {

    //用HashMap存储SharedFlow
    private val flowEvents = ConcurrentHashMap<String, MutableSharedFlow<Event>>()

    //获取Flow,当相应Flow不存在时创建
    fun getFlow(key: String): MutableSharedFlow<Event> {
        return flowEvents[key] ?: MutableSharedFlow<Event>().also { flowEvents[key] = it }
    }

    // 发送事件
    fun post(event: Event, delay: Long = 0) {
        MainScope().launch {
            delay(delay)
            getFlow(event.javaClass.simpleName).emit(event)
        }
    }

    // 订阅事件
    inline fun <reified T : Event> observe(
        lifecycleOwner: LifecycleOwner,
        minState: Lifecycle.State = Lifecycle.State.CREATED,
        dispatcher: CoroutineDispatcher = Dispatchers.Main,
        crossinline onReceived: (T) -> Unit
    ) = lifecycleOwner.lifecycleScope.launch(dispatcher) {
        getFlow(T::class.java.simpleName).collect {
            lifecycleOwner.lifecycle.whenStateAtLeast(minState) {
                if (it is T) onReceived(it)
            }
        }
    }

}