Kotlin EventEmitter类:如何存储不同类型事件监听器?
实现Kotlin EventEmitter:替换TODO及函数存储方案
一、替换代码中的TODO
先拆解你代码里的两个TODO,一步步修正:
1. listeners的类型定义
一个事件通常可以绑定多个监听器,所以不能直接存单个函数,应该用监听器列表来存储。这里的TODO要替换为MutableList<(Any?) -> Unit>,最终listeners的定义是:
private val listeners: MutableMap<String, MutableList<(Any?) -> Unit>> = mutableMapOf()
用(Any?) -> Unit是因为不同事件可能接收不同类型的参数,这样能兼容所有类型的监听器函数。
2. emit函数的实现
emit的核心是触发指定事件的所有监听器,并返回是否存在该事件的监听器。实现逻辑如下:
- 先从
listeners中获取当前事件的监听器列表 - 如果列表为空,直接返回
false - 遍历列表中的每个监听器,调用并传入参数
arg - 最后返回
true
同时还要修正on函数的问题:原来的listeners.set(event, listener)会直接覆盖之前的监听器,正确的做法是先获取或创建事件对应的列表,再添加新的监听器,还要处理maxListeners的限制(超过数量时打印警告)。
修正后的完整代码片段:
open class EventEmitter( var maxListeners: Int = defaultMaxListeners ) { companion object { const val defaultMaxListeners = 10 } private val listeners: MutableMap<String, MutableList<(Any?) -> Unit>> = mutableMapOf() fun <T> on(event: String, listener: (T) -> Unit) { val eventListeners = listeners.getOrPut(event) { mutableListOf() } // 处理最大监听器数量限制 if (eventListeners.size >= maxListeners) { println("Warning: Event '$event' has reached max listeners ($maxListeners)") } // 将泛型监听器转换为兼容类型添加到列表 eventListeners.add { arg -> listener(arg as T) } } fun <T> emit(event: String, arg: T): Boolean { val eventListeners = listeners[event] ?: return false // 遍历调用所有监听器 eventListeners.forEach { it(arg) } return true } }
二、其他存储相似函数的方法
除了上面用MutableMap<String, MutableList<...>>的基础方案,还有几种常见的替代方式:
- 使用Multimap:如果不想手动维护Map+List的结构,可以用Guava库的
Multimap<String, (Any?) -> Unit>,它本质是对“键对应多个值”的封装,能简化添加、删除监听器的操作。 - 封装监听器接口:定义一个专门的函数式接口,比如:
然后存储fun interface EventListener<T> { fun onEvent(arg: T) }MutableMap<String, MutableList<EventListener<*>>>,这种方式类型更明确,适合需要统一管理监听器生命周期的场景。 - 弱引用存储:如果担心监听器导致内存泄漏,可以用
MutableList<WeakReference<(Any?) -> Unit>>存储监听器的弱引用,每次调用前先清理已被回收的引用。 - 协程Channel(异步场景):如果是异步事件场景,可以为每个事件创建一个
Channel<T>,监听器通过receive接收事件,emit则通过send发送事件,这种方式天然支持异步处理。
内容的提问来源于stack exchange,提问作者Alex Klimashevsky
相关产品推荐
相关产品推荐

