让你的App消息分发又快又稳:EventBus框架核心原理与实现全流程
在上一篇文章中,我们详细剖析了观察者模式的各种实现方式及其应用场景。今天,我们聚焦一个更工程化、更实用的高阶用法:如何在移动端实现一个异步非阻塞、线程安全、易用的事件总线(EventBus)框架。
无论是 App 组件间解耦、全局事件传递、跨模块消息通知,还是响应式业务链路,EventBus 都是现代移动端架构的核心武器。本篇将结合 Swift 和 Kotlin 实战案例,通俗详解 EventBus 的设计要点与落地方案,让你轻松实现高性能、低耦合的消息驱动体系。
一、什么是 EventBus?为何需要异步非阻塞?
1.1 传统观察者模式的局限
- o 多为同步通知,主线程阻塞,事件响应慢。
- o 需要手动管理观察者列表,跨线程容易出错。
- o 对复杂事件流和多线程场景支持有限。
1.2 EventBus 的优势
- o 异步非阻塞:事件推送/分发不会阻塞业务线程。
- o 线程安全:支持多线程并发订阅和推送。
- o 解耦彻底:发布者与订阅者无需互相感知,跨模块事件灵活传递。
- o 灵活分发:支持单播/广播、优先级、粘性事件、主线程/UI线程分发等特性。
二、EventBus 核心设计思路
2.1 角色抽象
- o EventBus:核心消息总线,负责注册、反注册、分发事件。
- o Subscriber/Listener:事件订阅者,响应特定类型的事件。
- o Event/EventType:事件本体,通常是 struct/class,可包含业务数据。
2.2 基本 API 设计
- o register(subscriber: EventListener, for type: EventType)
- o unregister(subscriber: EventListener, for type: EventType)
- o post(event: Event)
- o 支持主线程、子线程、延迟/粘性事件等可选特性
三、Swift 实现:异步 EventBus 基础框架
3.1 事件协议
protocol Event { }
3.2 订阅者协议
protocol EventListener: AnyObject {
func onEvent(_ event: Event)
}
3.3 EventBus 主体
import Foundation
class EventBus {
static let shared = EventBus()
private var listeners: [String: NSHashTable<AnyObject>] = [:]
private let queue = DispatchQueue(label: "eventbus.queue", attributes: .concurrent)
func register<T: Event>(_ listener: EventListener, for eventType: T.Type) {
let key = String(describing: eventType)
queue.async(flags: .barrier) {
let table = self.listeners[key] ?? NSHashTable.weakObjects()
table.add(listener)
self.listeners[key] = table
}
}
func unregister<T: Event>(_ listener: EventListener, for eventType: T.Type) {
let key = String(describing: eventType)
queue.async(flags: .barrier) {
self.listeners[key]?.remove(listener)
}
}
func post(_ event: Event) {
let key = String(describing: type(of: event))
queue.async {
guard let listeners = self.listeners[key] else { return }
for listener in listeners.allObjects {
(listener as? EventListener)?.onEvent(event)
}
}
}
}
3.4 用法示例
struct LoginEvent: Event {
let userId: String
}
class HomeViewModel: EventListener {
init() {
EventBus.shared.register(self, for: LoginEvent.self)
}
func onEvent(_ event: Event) {
if let login = event as? LoginEvent {
print("登录成功,用户ID:\(login.userId)")
}
}
}
let vm = HomeViewModel()
EventBus.shared.post(LoginEvent(userId: "12345"))
四、Kotlin 实现:高性能 EventBus 方案
4.1 事件基类
interface Event
4.2 订阅者接口
interface EventListener {
fun onEvent(event: Event)
}
4.3 EventBus 主体
object EventBus {
private val listeners = mutableMapOf<Class<out Event>, MutableList<EventListener>>()
private val lock = Any()
fun <T : Event> register(eventType: Class<T>, listener: EventListener) {
synchronized(lock) {
val list = listeners.getOrPut(eventType) { mutableListOf() }
if (!list.contains(listener)) list.add(listener)
}
}
fun <T : Event> unregister(eventType: Class<T>, listener: EventListener) {
synchronized(lock) {
listeners[eventType]?.remove(listener)
}
}
fun post(event: Event) {
val eventType = event.javaClass
val list = listeners[eventType]?.toList() ?: return
// 异步分发
Thread {
list.forEach { it.onEvent(event) }
}.start()
}
}
4.4 用法示例
data class LoginEvent(val userId: String) : Event
class HomeViewModel : EventListener {
init {
EventBus.register(LoginEvent::class.java, this)
}
override fun onEvent(event: Event) {
if (event is LoginEvent) {
println("登录成功,用户ID:${event.userId}")
}
}
}
val vm = HomeViewModel()
EventBus.post(LoginEvent("10086"))
五、进阶与优化建议
5.1 支持主线程分发(Swift)
func post(_ event: Event, onMainThread: Bool = false) {
let key = String(describing: type(of: event))
queue.async {
guard let listeners = self.listeners[key] else { return }
for listener in listeners.allObjects {
let call = { (listener as? EventListener)?.onEvent(event) }
if onMainThread {
DispatchQueue.main.async { call() }
} else {
call()
}
}
}
}
5.2 支持主线程分发(Kotlin/Android)
fun post(event: Event, onMainThread: Boolean = false) {
val eventType = event.javaClass
val list = listeners[eventType]?.toList() ?: return
if (onMainThread) {
Handler(Looper.getMainLooper()).post {
list.forEach { it.onEvent(event) }
}
} else {
Thread {
list.forEach { it.onEvent(event) }
}.start()
}
}
5.3 粘性事件、优先级等可扩展
- o 可为事件类型增加优先级队列、支持事件持久化,满足极端业务。
- o 推荐搭配 Swift 的 Combine/NotificationCenter、Kotlin 的 Flow/LiveData,灵活结合。
六、工程实践最佳建议
- o 弱引用管理:防止订阅者未释放导致内存泄漏。
- o 线程安全:所有订阅/注销/分发均需加锁或用并发队列。
- o 解耦利器:跨页面、跨模块通信 EventBus 极为高效,推荐优先用事件驱动取代直接依赖。
- o 结合响应式编程:对于高频事件/复杂业务建议基于 Combine/Flow 进一步封装,实现更强表达力。
七、结语
EventBus 不只是观察者模式的“进化体”,更是现代移动端 App 架构解耦、提升工程可维护性和响应能力的必备利器。希望通过本篇详解,你能掌握异步、非阻塞的事件驱动体系,并能灵活落地于自己的 Swift 或 Kotlin 项目,打造更优雅、健壮的 App!