subscribe

inline fun <E : Event> subscribe(coroutineContext: CoroutineContext = EmptyCoroutineContext, concurrency: ConcurrencyKind = LOCKED, priority: EventPriority = EventPriority.NORMAL, noinline handler: suspend E.(E) -> ListeningStatus): Listener<E>

创建一个事件监听器, 监听事件通道中所有 E 及其子类事件.

每当 事件广播 时, handler 都会被执行.

创建监听

调用本函数:

eventChannel.subscribe<E> { /* 会收到此通道中的所有是 E 的事件 */}

生命周期

通过协程作用域管理监听器

本函数将会创建一个 Job, 成为 parentJob 中的子任务. 可创建一个 CoroutineScope 来管理所有的监听器:

val scope = CoroutineScope(SupervisorJob())

val scopedChannel = eventChannel.parentScope(scope) // 将协程作用域 scope 附加到这个 EventChannel

scopedChannel.subscribeAlways<MemberJoinEvent> { /* ... */} // 启动监听, 监听器协程会作为 scope 的子任务
scopedChannel.subscribeAlways<MemberMuteEvent> { /* ... */} // 启动监听, 监听器协程会作为 scope 的子任务

scope.cancel() // 停止了协程作用域, 也就取消了两个监听器

这个函数返回 Listener, 它是一个 CompletableJob. 它会成为 parentJobparentScope 的一个 子任务

停止监听

如果 handler 返回 ListeningStatus.STOPPED 监听器将被停止.

也可以通过 subscribe 返回值 ListenerListener.complete

监听器调度

监听器会被创建一个协程任务, 语义上在 parentScope 下运行. 通过 Kotlin 默认协程调度器 在固定的全局共享线程池里执行, 除非有 coroutineContext 指定.

默认在 handler 中不能处理阻塞任务. 阻塞任务将会阻塞一个 Kotlin 全局协程调度线程并可能导致严重问题. 请通过 withContext(Dispatchers.IO) { } 等方法执行阻塞工作.

异常处理

  • 当参数 handler 处理抛出异常时, 将会按如下顺序寻找 CoroutineExceptionHandler 处理异常:

  1. 参数 coroutineContext

  2. EventChannel.defaultCoroutineContext

  3. Event.broadcast 调用者的 coroutineContext

  4. 若事件为 BotEvent, 则从 BotEvent.bot 获取到 Bot, 进而在 Bot.coroutineContext 中寻找

  5. 若以上四个步骤均无法获取 CoroutineExceptionHandler, 则使用 MiraiLogger.Companion 通过日志记录. 但这种情况理论上不应发生.

事件处理时抛出异常不会停止监听器.

建议在事件处理中 (即 handler 里) 处理异常, 或在参数 coroutineContext 中添加 CoroutineExceptionHandler, 或通过 EventChannel.exceptionHandler.

并发安全性

基于 concurrency 参数, 事件监听器可以被允许并行执行.

Return

监听器实例. 此监听器已经注册到指定事件上, 在事件广播时将会调用 handler

See also

挂起当前协程, 监听一个事件, 并尝试从这个事件中同步一个值

异步监听一个事件, 并尝试从这个事件中获取一个值.

挂起当前协程, 直到监听到事件 E 的广播, 返回这个事件实例.

when 的语法 '选择' 即将到来的一条消息.

when 的语法 '选择' 即将到来的所有消息, 直到不满足筛选结果.

监听消息 DSL

Parameters

coroutineContext

defaultCoroutineContext 的基础上, 给事件监听协程的额外的 CoroutineContext.

concurrency

并发类型. 查看 ConcurrencyKind

priority

监听优先级,优先级越高越先执行

handler

事件处理器. 在接收到事件时会调用这个处理器. 其返回值意义参考 ListeningStatus. 其异常处理参考上文


fun <E : Event> subscribe(eventClass: KClass<out E>, coroutineContext: CoroutineContext = EmptyCoroutineContext, concurrency: ConcurrencyKind = LOCKED, priority: EventPriority = EventPriority.NORMAL, handler: suspend E.(E) -> ListeningStatus): Listener<E>

subscribe 的区别是接受 eventClass 参数, 而不使用 reified 泛型. 通常推荐使用具体化类型参数.

Return

监听器实例. 此监听器已经注册到指定事件上, 在事件广播时将会调用 handler

See also


fun <E : Event> subscribe(eventClass: <ERROR CLASS><out E>, coroutineContext: CoroutineContext = EmptyCoroutineContext, concurrency: ConcurrencyKind = CONCURRENT, priority: EventPriority = EventPriority.NORMAL, handler: <ERROR CLASS><E, ListeningStatus>): Listener<E>

Java API. 查看 subscribe 获取更多信息.

eventChannel.subscribe(GroupMessageEvent.class, (event) -> {
return ListeningStatus.LISTENING;
});

See also