一、注解
首先声明一个注解:
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class Subscribe
Retention 表示此注解会在运行时保留,Target 表示此注解作用于方法上。
二、KEventBus
object KEventBus {
private val subscriptionsByEventType = mutableMapOf<Class<*>, MutableList<Pair<Any, Method>>>()
fun register(obj: Any) {
// Reflect to get all subscribed methods
obj.javaClass.declaredMethods.forEach {
if (it.isAnnotationPresent(Subscribe::class.java)) {
if (it.parameterTypes.size == 1) {
val eventType = it.parameterTypes.first()
if (eventType !in subscriptionsByEventType) {
subscriptionsByEventType[eventType] = mutableListOf()
}
subscriptionsByEventType[eventType]!!.add(obj to it)
}
}
}
}
fun unregister(obj: Any) {
obj.javaClass.declaredMethods.forEach {
if (it.isAnnotationPresent(Subscribe::class.java)) {
if (it.parameterTypes.size == 1) {
val event = it.parameterTypes.first()
if (event in subscriptionsByEventType) {
subscriptionsByEventType[event]?.remove(obj to it)
}
}
}
}
}
fun post(event: Any) {
subscriptionsByEventType[event.javaClass]?.forEach {
it.second.invoke(it.first, event)
}
}
}
EventBus 是一个典型的观察者模式,当某个 Class register 时,首先会遍历一次此 Class 中的所有方法,将带有 @Subscribe
注解的方法找到,将其注册到此方法的参数类型上。也就是生成了一个 参数类型 -> 所有观察者方法
的 Map。
当 post 消息时,找到此消息类型的所有观察者,依次调用这些观察者方法,将消息作为参数传入。
取消注册就是将对应的观察者移除。
三、使用
注册:
KEventBus.register(this)
发送消息:
KEventBus.post("I'm a string message")
接收消息:
@Subscribe
fun onStringEvent(message: String) {
Log.d("EventBus", message)
}
取消注册:
KEventBus.unregister(this)
四、后记
本文只是讲出 EventBus 的核心思想。在实际的 EventBus 中,还做了非常多的优化。主要有:
- 提供线程切换
- 提供 Sticky 消息
- 保证线程安全
- 用注解处理器生成 index 文件来获取订阅方法,以替代反射,提高性能。
网友评论