Android 处理Kotlin中事件总线的通用侦听器
我的目标是在Kotlin中实现非常简单的事件总线,而不需要任何第三方库。我用下面的代码实现了这一点Android 处理Kotlin中事件总线的通用侦听器,android,generics,events,kotlin,jvm,Android,Generics,Events,Kotlin,Jvm,我的目标是在Kotlin中实现非常简单的事件总线,而不需要任何第三方库。我用下面的代码实现了这一点 class EventListener<T>( val owner: Any, val event: Class<T>, val callback: (T) -> Unit ) interface IEventBus { fun <T> subscribe(owner: Any, event: Class<T>
class EventListener<T>(
val owner: Any,
val event: Class<T>,
val callback: (T) -> Unit
)
interface IEventBus {
fun <T> subscribe(owner: Any, event: Class<T>, callback: (T) -> Unit)
fun unsubscribe(owner: Any)
fun <T> push(event: T)
}
class EventBus : IEventBus {
private val _listeners = mutableListOf<EventListener<*>>()
override fun <T> subscribe(owner: Any, event: Class<T>, callback: (T) -> Unit) {
val listener = EventListener(owner, event, callback)
_listeners.add(listener)
}
override fun unsubscribe(owner: Any) {
_listeners.removeAll {
it.owner == owner
}
}
override fun <T> push(event: T) {
_listeners.forEach { listener ->
try {
val l = listener as EventListener<T> // is always a success
l.callback(event) // throws an exception if can't handle the event
} catch (ex: Exception) { }
}
}
}
它的工作,是完全可用的,但我不满意它。。。将侦听器转换为EventListener将始终返回某些内容,如果l.callback(event)无法处理事件类型,它将抛出异常。因此,如果有许多侦听器订阅,那么它将生成许多不需要的异常,这些异常将被忽略
我更愿意先做一些检查,比如:
if (listener is EventListener<T>)
listener.callback(event)
if(侦听器是EventListener)
回调(事件)
但是我发现JVM在编译之后丢失了关于泛型类型的信息。我还发现,使用kotlin的内联和具体化可以绕过它,但是这些不能用于来自接口的方法
因此,我的问题是,您知道处理此类泛型问题的更优雅的方法吗?既然您已经公开了事件的类(
EventListener\event
),您可以使用isInstance()
检查该类是否与事件实例的赋值兼容
因此,不是:
if (listener is EventListener<T>)
listener.callback(event)
if(侦听器是EventListener)
回调(事件)
你可以做:
if (listener.event.isInstance(event)) {
// The cast is safe since you checked if the event can be received by the listener.
(listener as EventListener<T>).callback(event)
}
if(listener.event.isInstance(event)){
//强制转换是安全的,因为您检查了侦听器是否可以接收事件。
(侦听器作为EventListener)。回调(事件)
}
基本体
如果您想支持原语类型的T
,可以将Class
更改为KClass
,或者手动检查每个原语类型的实例(例如事件为Int
,事件为Long
)。的文档包含一个简单的示例:
SharedFlow对于广播在内部发生的事件非常有用
应用程序到可以来去的订阅者。例如
下面的类封装了一个事件总线,该总线将事件分发给
所有订阅者会合,暂停,直到所有订阅者
订阅服务器处理每个事件:
class事件总线{
private val _events=MutableSharedFlow()//私有可变共享流
val events=\u events.asSharedFlow()//作为只读共享流公开
暂停趣味产品事件(事件:事件){
_events.emit(event)//挂起,直到所有订阅者都收到它
}
}
此外,也很有用。但是它似乎在Int.Int::class.java.isInstance(5)方面有问题false@DawidGrajewski这是因为Kotlin中的
Int
既可以引用原语JavaInt
,也可以引用装箱的JavaInteger
。如果您想支持原语,有两种可能:用KClass
替换Class
,或者检查事件是否可分配给原语类型。例如,事件为Int
,事件为Long
。如果可以,显然我建议您将Class
更改为KClass
,因为这样可以避免对基本类型进行所有检查。再次感谢您!这对我来说就结束了。祝你过得愉快:)
if (listener.event.isInstance(event)) {
// The cast is safe since you checked if the event can be received by the listener.
(listener as EventListener<T>).callback(event)
}
class EventBus {
private val _events = MutableSharedFlow<Event>() // private mutable shared flow
val events = _events.asSharedFlow() // publicly exposed as read-only shared flow
suspend fun produceEvent(event: Event) {
_events.emit(event) // suspends until all subscribers receive it
}
}