Kotlin Academy · Lezione

SharedFlow: event bus ed eventi one-shot

Configuri replay e extraBufferCapacity di SharedFlow per la diffusione degli eventi.

Lezione 2 di 413 passaggi

SharedFlow: event bus ed eventi one-shot è una lezione Kotlin Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Kotlin Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Kotlin Academy include 4 lezioni in totale.

Che cos'è SharedFlow?

SharedFlow è un Flow hot che trasmette gli eventi a tutti i collector attivi. A differenza di StateFlow, non gestisce un valore corrente: è puramente basato sugli eventi.

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()
}

Parametro replay

replay memorizza nel buffer le ultime N emissioni. I nuovi collector ricevono immediatamente fino a N eventi passati. Il valore predefinito è 0 (nessuna riproduzione).

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 aggiunge spazio al buffer oltre a quello di replay. I mittenti possono emettere senza sospendersi finché il buffer non è pieno.

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 per un'emissione non sospensiva

tryEmit(value) emette senza sospendersi e restituisce false se il buffer è pieno. Lo utilizzi nei contesti non sospensivi, come callback e gestori dei clic.

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()
}

Eventi una tantum (navigazione dell'interfaccia utente)

Utilizzi SharedFlow con replay=0 per gli eventi una tantum dell'interfaccia utente, come la navigazione o la visualizzazione di uno Snackbar: gli eventi non vengono riprodotti durante la ricomposizione.

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 rispetto a StateFlow

StateFlow: stato con valore corrente (stato dell'interfaccia utente). SharedFlow: eventi senza persistenza (navigazione, Snackbar, analisi). Scelga in base alla necessità dei consumer di ricevere o meno il valore più recente.

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") }

Event bus con SharedFlow

Implementi un semplice event bus a livello di applicazione usando un SharedFlow singleton, in sostituzione dei modelli basati su PublishSubject di 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 è uno StateFlow che tiene traccia del numero di collector attivi, utile per avviare o arrestare i produttori 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() cancella la cache di replay nel buffer, utile quando gli eventi da riprodurre non sono più aggiornati e i nuovi sottoscrittori non devono visualizzarli.

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}")  // []
}

Gestire la backpressure in SharedFlow

Quando i collettori sono lenti, utilizzi onBufferOverflow per scegliere tra: SUSPEND (predefinito), 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()
}

Raccolta con timeout

Raccolga un SharedFlow con un timeout per elaborare un numero finito di eventi e poi interrompere la raccolta, una soluzione utile per i test o per un'elaborazione vincolata.

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")
}

Verifica rapida

Quale valore di replay è opportuno utilizzare per eventi UI una tantum, come la navigazione?

Riepilogo

SharedFlow è un broadcaster di eventi hot. Utilizzi replay=0 per gli eventi una tantum e replay>0 per i sottoscrittori che arrivano in ritardo. Utilizzi tryEmit nei contesti non sospendibili. Scelga SharedFlow per gli eventi e StateFlow per lo stato.

Gratis per iniziare

Impara Kotlin con un tutor IA — gratis

Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.

Corsi
51
Lezioni
203

Domande Frequenti

La lezione «SharedFlow: event bus ed eventi one-shot» è gratuita?

Sì — il testo completo di «SharedFlow: event bus ed eventi one-shot» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Kotlin Academy, passa a CoddyKit PRO. Il corso Kotlin Academy include 4 lezioni in totale.

Cosa imparerò in «SharedFlow: event bus ed eventi one-shot»?

Configuri replay e extraBufferCapacity di SharedFlow per la diffusione degli eventi. Eserciti Kotlin Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Kotlin Academy?

Non è richiesta alcuna esperienza precedente. Kotlin Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.

Quanto tempo richiede la lezione «SharedFlow: event bus ed eventi one-shot»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Kotlin Academy?

Sì. Ogni lezione Kotlin Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. StateFlow: contenitore hot dello stato per l'interfaccia
  2. SharedFlow: event bus ed eventi one-shot
  3. Convertire un Flow cold in hot con shareIn e stateIn
  4. Testare StateFlow e SharedFlow con Turbine
← Torna a Kotlin Academy