一、背景介绍

在Android开发中,组件间通信一直是核心挑战之一。传统的Intent传递数据不仅代码冗余,还会导致组件间强耦合;Handler机制则局限于单一进程内的线程通信;而BroadcastReceiver虽然支持跨进程,但性能开销较大且使用复杂。

随着应用架构日益复杂,我们需要一个更轻量、高效且低侵入的事件通信方案。Bus框架应运而生,它借鉴了事件驱动设计模式,通过统一的事件总线实现组件解耦,同时支持进程内和跨进程通信场景。

二、Bus框架核心特性

Bus框架是一个基于Kotlin开发的Android事件通信库,主要特点包括:

  • 双总线设计:提供LocalBus(进程内高性能通信)和BroadcastBus(跨进程通信)两种实现

  • 零侵入API:通过接口定义事件,无需继承特定基类

  • 生命周期感知:支持与Activity/Fragment生命周期自动绑定,避免内存泄漏

  • 线程安全:内部使用ConcurrentHashMap和CopyOnWriteArrayList保证多线程安全

  • 粘性事件:支持事件缓存,确保新注册的监听器能接收历史事件

  • 优先级机制:允许设置监听器优先级,控制事件分发顺序

三、核心接口与类结构

1. 核心接口定义

interface IBus {
    // 发送事件
    fun send(event: Event, extras: Bundle? = null)
    fun send(event: Event, vararg pairs: Pair<String, @Serializable Any>)

    // 发送粘性事件
    fun sendSticky(event: Event, extras: Bundle? = null)
    fun sendSticky(event: Event, vararg pairs: Pair<String, @Serializable Any>)

    // 注册监听器
    fun register(priority: Int, vararg events: Event, listener: OnBusEventListener): IBusUnRegisterable
    fun registerSticky(priority: Int, vararg events: Event, listener: OnBusEventListener): IBusUnRegisterable

    // 注销监听器
    fun unregister(listener: OnBusEventListener?)

    interface Event {
        fun getId(): String
    }

    fun interface OnBusEventListener {
        fun onBusEvent(event: Event, extras: Bundle?): Boolean
    }
}

2. 类层次结构

IBus
├── BaseBus (抽象基类,实现公共逻辑)
│   ├── LocalBus (进程内通信实现)
│   └── BroadcastBus (跨进程通信实现)
└── IBusRegisterable (注册管理接口)
    ├── BusLifecycleRegisterable (生命周期绑定)
    ├── BusViewRegisterable (View绑定)
    └── BusCoroutineRegisterable (协程绑定)

四、实现思路详解

1. 数据结构设计

框架核心采用以下数据结构管理事件与监听器:

// 事件与监听器映射表 (key: eventId, value: 监听器列表)
protected val eventListenerMap = ConcurrentHashMap<String, CopyOnWriteArrayList<ListenerHolder>>()

// 监听器与事件映射表 (用于快速注销)
protected val listenerEventMap = ConcurrentHashMap<IBus.OnBusEventListener, MutableSet<String>>()

// 粘性事件缓存
protected val stickyEventMap = ConcurrentHashMap<String, Pair<IBus.Event, Bundle?>>()

使用ConcurrentHashMap保证线程安全,CopyOnWriteArrayList避免迭代过程中的并发修改异常。

2. 事件发送流程

LocalBus实现(主线程分发):

override fun sendInternal(event: IBus.Event, extras: Bundle?, cacheSticky: Boolean) {
    ThreadUtils.runOnMainThread {
        val eventId = event.getId()
        if (cacheSticky) {
            stickyEventMap[eventId] = Pair(event, extras)
        }
        // 获取监听器并按优先级排序分发
        eventListenerMap[eventId]?.sortedByDescending { it.priority }?.forEach {
            try {
                if (it.listener.onBusEvent(event, extras)) return@runOnMainThread
            } catch (e: Exception) {
                LogM.e(TAG, "Error calling listener for event: $eventId", e)
            }
        }
    }
}

BroadcastBus实现 (基于系统广播):

override fun sendInternal(event: IBus.Event, extras: Bundle?, cacheSticky: Boolean) {
    val eventId = event.getId()
    if (cacheSticky) {
        stickyEventMap[eventId] = Pair(event, extras)
    }
    try {
        val intent = Intent(ACTION).apply {
            setPackage(context.packageName)
            putExtra(EXTRA_EVENT, eventId)
            putExtra(EXTRA_DATA, extras)
        }
        context.sendBroadcast(intent)
    } catch (e: Exception) {
        LogM.e(TAG, "Error sending broadcast for event: $eventId", e)
    }
}

3. 监听器注册与注销

注册流程核心代码:

private fun internalRegister(
    priority: Int,
    events: Array<out IBus.Event>,
    listener: IBus.OnBusEventListener
) {
    events.forEach {
        val eventId = it.getId()
        val holders = eventListenerMap.getOrPut(eventId) { CopyOnWriteArrayList() }
        if (holders.none { h -> h.listener == listener }) {
            holders.add(ListenerHolder(priority, listener))
            listenerEventMap.getOrPut(listener) { ConcurrentHashMap.newKeySet() }.add(eventId)
        }
    }
}

注销实现:

override fun unregister(listener: IBus.OnBusEventListener?) {
    val eventIds = listenerEventMap.remove(listener) ?: return

    eventIds.forEach { eventId ->
        val holders = eventListenerMap[eventId]
        holders?.removeIf { it.listener == listener }
        if (holders.isNullOrEmpty()) {
            eventListenerMap.remove(eventId)
            onAllListenersRemovedForEvent(eventId)
        }
    }
}

五、生命周期管理机制

框架提供三种自动注销机制,有效避免内存泄漏:

1. 基于Lifecycle的注册器

class BusLifecycleRegisterable(
    private val lifecycle: Lifecycle,
    private val lifeEvent: Lifecycle.Event? = null
) : IBusRegisterable() {
    init {
        lifecycle.addObserver(object : LifecycleEventObserver {
            override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
                if (event == (lifeEvent ?: Lifecycle.Event.ON_DESTROY)) {
                    lifecycle.removeObserver(this)
                    unregister()
                }
            }
        })
    }
}

使用方式:

BusUtils.life(this).register(UserEvent.LOGIN) { event, extras ->
    // 处理登录事件
    false
}

2. View绑定的注册器

class BusViewRegisterable(private val view: View) : IBusRegisterable() {
    init {
        view.viewTreeObserver.addOnWindowAttachListener(object : ViewTreeObserver.OnWindowAttachListener {
            override fun onWindowDetached() {
                view.viewTreeObserver.removeOnWindowAttachListener(this)
                unregister()
            }
        })
    }
}

3. 协程作用域绑定

class BusCoroutineRegisterable(private val coroutineScope: CoroutineScope) : IBusRegisterable() {
    init {
        coroutineScope.coroutineContext[Job]?.invokeOnCompletion {
            if (it != null || coroutineScope.isActive.not()) {
                unregister()
            }
        }
    }
}

六、使用示例

1. 定义事件

enum class AppEvent : IBus.Event {
    DATA_UPDATE,
    NETWORK_STATE,
    USER_LOGIN;

    override fun getId(): String = name
}

2. 发送事件

// 发送普通事件
BusProvider.localBus.send(AppEvent.USER_LOGIN, "userId" to 123, "name" to "Han0")

// 发送粘性事件
BusProvider.localBus.sendSticky(AppEvent.NETWORK_STATE, "connected" to true)

3. 接收事件

override fun setBusListeners() {
    BusUtils.life(this).register(
        BusEventCommon.ShowMainLoading
    ) { event, extras ->
        when (event) {
            BusEventCommon.ShowMainLoading -> {
                val show = extras?.getBoolean("show") == true
                binding.lottieLoading.isVisible = show
                if (show) binding.lottieLoading.playAnimation() else binding.lottieLoading.cancelAnimation()
            }
        }
        false
    }
}

4. SP与事件自动绑定

通过SPBusEscrow实现事件驱动的SP存储:

class SPBusEscrow<T>(
    private val event: IBus.Event,
    private val defaultValue: T,
    key: SP.Key = SP.busEvent2Key(event),
    private val extractor: (Bundle?) -> T
) : SPEscrow<T>(key, defaultValue), IBus.OnBusEventListener {
    init {
        bus.register(priority, event, listener = this)
    }

    override fun onBusEvent(event: IBus.Event, extras: Bundle?): Boolean {
        val newValue = extractor(extras) ?: defaultValue
        SP.with(region)[key] = newValue
        return false
    }
}

使用示例:

var isDarkMode by SPBusEscrow(
    event = AppEvent.THEME_CHANGE,
    defaultValue = false,
    extractor = { it?.getBoolean("isDark") ?: false }
)

七、注意事项与最佳实践

事件命名规范:建议使用枚举类定义事件,确保唯一性

enum class NetworkEvent : IBus.Event {
    CONNECTED, DISCONNECTED, ERROR
}
  1. 优先级使用:重要监听器设置较高优先级,返回true可拦截事件

  2. 避免过度使用:UI状态变化优先使用ViewModel+LiveData,跨组件通信才使用Bus

  3. 数据类型限制:事件附加数据建议使用基础类型,复杂对象考虑序列化

  4. 调试技巧:通过getRegisteredEvents()getListenerCount()排查事件注册问题

  5. 跨进程选择:仅需进程内通信时使用LocalBus,性能优于BroadcastBus

八、扩展建议

  1. 添加事件节流机制,防止高频事件冲击

  2. 实现事件溯源功能,记录事件流转路径

  3. 增加单元测试覆盖率,特别是边界情况

  4. 开发编译期注解处理器,实现事件订阅代码自动生成

  5. 添加事件总线监控面板,可视化事件流向

总结

Bus框架通过简洁的API设计和灵活的扩展能力,为Android应用提供了统一的事件通信解决方案。其双总线架构兼顾了性能与功能扩展性,而生命周期绑定机制有效降低了内存泄漏风险。合理使用Bus框架可以显著降低组件耦合度,提升代码可维护性。

希望本教程能帮助开发者理解Bus框架的设计思想与使用方法。如有任何问题或建议,欢迎在评论区交流讨论!