SharedFlow: buses de eventos y eventos de una sola emisión
Configure replay y extraBufferCapacity de SharedFlow para difundir eventos.
SharedFlow: buses de eventos y eventos de una sola emisión es una lección gratuita de Kotlin Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Kotlin Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Kotlin Academy incluye 4 lecciones en total.
¿Qué es SharedFlow?
SharedFlow es un Flow caliente que difunde los valores a todos los colectores activos. A diferencia de StateFlow, no tiene el concepto de valor actual; funciona exclusivamente mediante eventos.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val events = MutableSharedFlow<String>()
launch { events.collect { println("Collector 1: $it") } }
launch { events.collect { println("Collector 2: $it") } }
delay(50)
events.emit("UserLoggedIn")
events.emit("DataRefreshed")
delay(50)
coroutineContext.cancelChildren()
}Parámetro replay
replay almacena en búfer las últimas N emisiones. Los nuevos colectores reciben inmediatamente hasta N eventos anteriores. El valor predeterminado es 0 (sin repetición).
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val flow = MutableSharedFlow<Int>(replay = 2)
flow.emit(1); flow.emit(2); flow.emit(3)
// Late subscriber gets last 2:
flow.collect { print("$it ") } // prints 2 3
}extraBufferCapacity
extraBufferCapacity añade espacio de búfer adicional al de replay. Los emisores pueden emitir sin suspenderse hasta que el búfer se llene.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val flow = MutableSharedFlow<Int>(
replay = 0,
extraBufferCapacity = 10
)
// Can emit up to 10 times without a collector ready:
repeat(10) { flow.tryEmit(it) }
launch { flow.collect { print("$it ") } }
delay(50)
coroutineContext.cancelChildren()
}tryEmit para emitir sin suspenderse
tryEmit(value) emite sin suspenderse y devuelve false si el búfer está lleno. Úselo en contextos que no sean suspend (callbacks, gestores de clics).
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val flow = MutableSharedFlow<String>(extraBufferCapacity = 5)
val ok = flow.tryEmit("click") // non-suspending
println("Emitted: $ok")
launch { flow.collect { println(it) } }
delay(50)
coroutineContext.cancelChildren()
}Eventos de una sola ejecución (navegación de la interfaz)
Use SharedFlow con replay=0 para eventos de una sola ejecución en la interfaz, como la navegación o mostrar un Snackbar; los eventos no se repiten al recomponerse la interfaz.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
class NavViewModel {
private val _events = MutableSharedFlow<String>()
val events = _events.asSharedFlow()
fun navigateTo(route: String) {
// viewModelScope.launch:
kotlinx.coroutines.GlobalScope.launch { _events.emit(route) }
}
}
// Collect in UI:
// viewModel.events.collect { route -> navController.navigate(route) }SharedFlow frente a StateFlow
StateFlow: estado con valor actual (estado de la interfaz). SharedFlow: eventos sin persistencia (navegación, Snackbar, analytics). Elija según si los consumidores necesitan el valor más reciente.
import kotlinx.coroutines.flow.*
// StateFlow: always has a value; new subscribers get current value
val uiState = MutableStateFlow("idle")
// SharedFlow: no stored value; events fire and are gone (unless replay>0)
val singleEvents = MutableSharedFlow<String>(replay = 0)
fun main() { println("State = what it is; Event = what happened") }Bus de eventos con SharedFlow
Implemente un bus de eventos sencillo para toda la aplicación mediante un SharedFlow singleton, sustituyendo los patrones de PublishSubject de RxJava.
import kotlinx.coroutines.flow.*
object EventBus {
private val _events = MutableSharedFlow<Any>(extraBufferCapacity = 100)
val events = _events.asSharedFlow()
fun post(event: Any) { _events.tryEmit(event) }
}
sealed class AppEvent {
object UserLoggedOut : AppEvent()
data class ShowError(val msg: String) : AppEvent()
}
// Usage: EventBus.post(AppEvent.UserLoggedOut)subscriptionCount
sharedFlow.subscriptionCount es un StateFlow que registra el número de colectores activos; resulta útil para iniciar o detener los productores upstream.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val flow = MutableSharedFlow<Int>()
println("Subscribers: ${flow.subscriptionCount.value}") // 0
val job = launch { flow.collect { } }
delay(50)
println("Subscribers: ${flow.subscriptionCount.value}") // 1
job.cancel()
delay(50)
println("Subscribers: ${flow.subscriptionCount.value}") // 0
}resetReplayCache
resetReplayCache() borra la caché de repetición almacenada en el búfer, lo que resulta útil cuando los eventos repetidos están obsoletos y los nuevos suscriptores no deben verlos.
import kotlinx.coroutines.flow.*
fun main() {
val flow = MutableSharedFlow<Int>(replay = 3)
flow.tryEmit(1); flow.tryEmit(2); flow.tryEmit(3)
println("Replay cache: ${flow.replayCache}") // [1, 2, 3]
flow.resetReplayCache()
println("Replay cache: ${flow.replayCache}") // []
}Gestión de la contrapresión en SharedFlow
Cuando los colectores son lentos, use onBufferOverflow para elegir entre: SUSPEND (opción predeterminada), DROP_OLDEST o DROP_LATEST.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.channels.BufferOverflow
fun main() = runBlocking {
val flow = MutableSharedFlow<Int>(
replay = 0,
extraBufferCapacity = 3,
onBufferOverflow = BufferOverflow.DROP_OLDEST
)
repeat(10) { flow.tryEmit(it) }
launch {
flow.collect { println(it) } // only sees most recent 3
}
delay(50)
coroutineContext.cancelChildren()
}Recopilación con tiempo de espera
Recopile un SharedFlow con un tiempo de espera para procesar una cantidad finita de eventos y detenerse después; resulta útil para pruebas o procesamiento limitado.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val events = MutableSharedFlow<String>()
launch { repeat(5) { delay(50); events.emit("Event $it") } }
withTimeoutOrNull(200) {
events.collect { println(it) }
}
println("Done collecting")
}Comprobación rápida
¿Qué valor de replay debe usar para eventos de UI de una sola emisión, como la navegación?
Resumen
SharedFlow es un emisor de eventos caliente. Use replay=0 para eventos de una sola emisión y replay>0 para suscriptores tardíos. Use tryEmit en contextos que no permiten suspender. Elija SharedFlow para eventos y StateFlow para estados.
Preguntas frecuentes
¿La lección «SharedFlow: buses de eventos y eventos de una sola emisión» es gratis?
Sí — el texto completo de «SharedFlow: buses de eventos y eventos de una sola emisión» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Kotlin Academy, actualiza a CoddyKit PRO. El curso de Kotlin Academy incluye 4 lecciones en total.
¿Qué aprenderé en «SharedFlow: buses de eventos y eventos de una sola emisión»?
Configure replay y extraBufferCapacity de SharedFlow para difundir eventos. Practicas Kotlin Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Kotlin Academy?
No se requiere experiencia previa. Kotlin Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.
¿Cuánto tiempo toma la lección «SharedFlow: buses de eventos y eventos de una sola emisión»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Kotlin Academy?
Sí. Cada lección de Kotlin Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- StateFlow: contenedor de estado activo para la interfaz
- SharedFlow: buses de eventos y eventos de una sola emisión
- Convertir Cold Flow en Hot con shareIn y stateIn
- Probar StateFlow y SharedFlow con Turbine