一、背景介绍
在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
}
优先级使用:重要监听器设置较高优先级,返回true可拦截事件
避免过度使用:UI状态变化优先使用ViewModel+LiveData,跨组件通信才使用Bus
数据类型限制:事件附加数据建议使用基础类型,复杂对象考虑序列化
调试技巧:通过
getRegisteredEvents()
和getListenerCount()
排查事件注册问题跨进程选择:仅需进程内通信时使用LocalBus,性能优于BroadcastBus
八、扩展建议
添加事件节流机制,防止高频事件冲击
实现事件溯源功能,记录事件流转路径
增加单元测试覆盖率,特别是边界情况
开发编译期注解处理器,实现事件订阅代码自动生成
添加事件总线监控面板,可视化事件流向
总结
Bus框架通过简洁的API设计和灵活的扩展能力,为Android应用提供了统一的事件通信解决方案。其双总线架构兼顾了性能与功能扩展性,而生命周期绑定机制有效降低了内存泄漏风险。合理使用Bus框架可以显著降低组件耦合度,提升代码可维护性。
希望本教程能帮助开发者理解Bus框架的设计思想与使用方法。如有任何问题或建议,欢迎在评论区交流讨论!