commonMain.io.github.lyxnx.util.EventBus.kt Maven / Gradle / Ivy
package io.github.lyxnx.util
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.filterIsInstance
import kotlin.coroutines.coroutineContext
import kotlin.jvm.JvmStatic
import kotlin.jvm.JvmSynthetic
/**
* An event bus that can be used with the subscriber/listener pattern
*
* It is important to think if an event bus is really needed, where a [Flow] or LiveData could be used instead.
*
* As such, an event bus is easily abused and if so, keeping track of state becomes harder and this can introduce unintended behaviour.
*
* Usage of an event bus should be limited to a certain number of global events. For example, the user has logged out, or
* the network status has changed.
*
* This should NOT be used to publish events to trigger a UI update - that is what a ViewModel is for.
*/
public object EventBus {
private val _events: MutableSharedFlow = MutableSharedFlow(extraBufferCapacity = 1)
@PublishedApi
internal val events: SharedFlow = _events.asSharedFlow()
/**
* Publishes [event] to this event bus
*/
@JvmSynthetic
public fun publish(event: Any) {
_events.tryEmit(event)
}
/**
* Subscribes to a specific event as a read-only [Flow]
*
* @param T type of event to subscribe to
*/
@JvmStatic
public inline fun subscribe(): Flow = events.filterIsInstance()
/**
* Subscribes to a specific event and calls [onEvent] on each event instance
*
* @param T type of event to subscribe to
*/
@JvmSynthetic
public suspend inline fun subscribe(crossinline onEvent: (T) -> Unit) {
subscribe()
.collectLatest { event ->
coroutineContext.ensureActive()
onEvent(event)
}
}
}