# Kotlin Flow vs StateFlow vs SharedFlow: Android-interviewvragen in 2026 > De Kotlin Flow vs StateFlow vs SharedFlow-vragen die Android-interviewers in 2026 stellen, met heldere antwoorden, een vergelijkingstabel en productieklare code. - Published: 2026-07-01 - Updated: 2026-07-07 - Author: SharpSkill - Tags: android, kotlin, coroutines, flow, interview - Reading time: 9 min --- Kotlin Flow vs StateFlow vs SharedFlow is een van de vaakst voorkomende onderwerpen tijdens Android-sollicitatiegesprekken in 2026, en de drie door elkaar halen kost al snel een coroutines-ronde. StateFlow en SharedFlow zijn allebei hot streams die op Flow zijn gebouwd, maar ze bestaan om verschillende problemen op te lossen: state vasthouden versus events uitzenden. De onderstaande vragen zijn de vragen die Android-interviewers daadwerkelijk stellen, met precieze antwoorden en productieklare code. > **Het antwoord in 20 seconden** > > Een `Flow` is cold en draait de producer één keer per collector. `StateFlow` is een hot, geconflateerde stream die altijd één huidige waarde vasthoudt, ideaal voor UI-state. `SharedFlow` is een hot stream zonder verplichte beginwaarde, ideaal voor eenmalige events zoals navigatie of een snackbar. ## Kotlin Flow vs StateFlow vs SharedFlow: de kernverschillen StateFlow en SharedFlow zijn specialisaties van `SharedFlow`, dat zelf een hot `Flow` is. Waar interviewers naar peilen is cold versus hot, of er een huidige waarde bewaard blijft, en hoe elk type omgaat met dubbele emissies. Een beknopt mentaal model: `Flow` is een recept, `StateFlow` is één enkele mutable waarde en `SharedFlow` is een event bus. | Eigenschap | Flow (cold) | StateFlow | SharedFlow | |---|---|---|---| | Temperatuur | Cold | Hot | Hot | | Beginwaarde | Geen | Verplicht | Optioneel (via `replay`) | | Houdt huidige waarde vast | Nee | Ja, via `.value` | Nee | | Zendt duplicaten uit | Ja | Nee (geconflateerd + ontdubbeld) | Instelbaar | | Extra collectors | Elke keer een nieuwe stream | Gedeeld | Gedeeld | | Geschikt voor | Async datapijplijnen | UI-state | Eenmalige events | De [officiële Kotlin-coroutinesdocumentatie](https://kotlinlang.org/docs/flow.html) beschouwt dit cold-by-default-gedrag als de bepalende eigenschap van `Flow`, dus een sterk antwoord begint daar. ## Waarom is een Kotlin Flow standaard cold? Een cold flow doet niets totdat `collect()` wordt aangeroepen, en voert zijn producerblok opnieuw uit voor elke collector. Twee collectors op dezelfde cold flow veroorzaken twee onafhankelijke netwerkaanroepen. Dit is het meest geteste concept, dus een kort voorbeeld verankert het antwoord. ```kotlin // SearchRepository.kt fun searchResults(query: String): Flow> = flow { // This block runs fresh for every collector. // Nothing executes until a collector calls collect(). val results = api.search(query) // suspending network call emit(results) // pushed downstream to the collector } ``` Doordat de producer per collector opnieuw start, zijn cold flows de juiste standaard voor datapijplijnen die op aanvraag moeten draaien. Ze worden pas een probleem wanneer een waarde over een heel scherm gedeeld moet worden, en precies daar komen StateFlow en SharedFlow in beeld. ## StateFlow-interviewvragen: state die altijd een waarde uitzendt `StateFlow` is een hot flow die altijd een waarde heeft en die laatste waarde opnieuw afspeelt naar elke nieuwe collector. Het vereist een beginwaarde, stelt `.value` beschikbaar voor synchrone reads en conflateert emissies: snelle opeenvolgende updates kunnen tussenliggende waarden overslaan, en dezelfde waarde twee keer instellen zendt niets uit omdat er op basis van gelijkheid wordt ontdubbeld. Daarmee is het de moderne vervanger van `LiveData` in een `ViewModel`. ```kotlin // SearchViewModel.kt class SearchViewModel(private val repo: SearchRepository) : ViewModel() { // MutableStateFlow demands an initial value, so the UI always has something to render. private val _uiState = MutableStateFlow(SearchUiState.Idle) val uiState: StateFlow = _uiState.asStateFlow() fun onQueryChanged(query: String) { _uiState.value = SearchUiState.Loading viewModelScope.launch { val results = repo.search(query) // update {} applies the change atomically, safe under concurrent callers. _uiState.update { SearchUiState.Success(results) } } } } ``` Een veelgestelde vervolgvraag: waarom `asStateFlow()` blootstellen in plaats van het mutable veld? Het geeft de UI een alleen-lezen weergave, zodat de state alleen via de ViewModel kan wijzigen, wat de unidirectionele data flow intact houdt. De eigen [StateFlow- en SharedFlow-gids](https://developer.android.com/kotlin/flow/stateflow-and-sharedflow) van Android beveelt precies dit patroon aan. ## SharedFlow vs StateFlow: het juiste type kiezen voor events De klassieke valstrikvraag luidt: "kan StateFlow eenmalige events leveren?" Het eerlijke antwoord is nee, niet veilig. Omdat StateFlow conflateert en ontdubbelt, kan een navigatie-event bij snelle updates verloren gaan, en het vuurt opnieuw af bij een configuratiewijziging omdat een nieuwe collector de bewaarde waarde opnieuw afspeelt. `SharedFlow` met `replay = 0` lost beide op: er wordt niets bewaard, en elke emissie bereikt alleen de collectors die actief zijn op het moment van uitzenden. ```kotlin // CheckoutViewModel.kt class CheckoutViewModel : ViewModel() { // replay = 0: a late collector must NOT re-receive a past navigation event. private val _events = MutableSharedFlow(replay = 0) val events: SharedFlow = _events.asSharedFlow() fun onPaymentConfirmed() { viewModelScope.launch { // emit() suspends if the buffer is full; tryEmit() is the non-suspending variant. _events.emit(CheckoutEvent.NavigateToReceipt) } } } ``` Voor architectuurvragen komt de diepere redenering achter het scheiden van state en events terug in de [vergelijking MVVM vs MVI](/blog/android/mvvm-vs-mvi-architecture), waar MVI events als een expliciete stream behandelt in plaats van als mutable state. ## Een cold Flow omzetten naar een hot StateFlow met stateIn Interviewers vragen vaak hoe je de cold flow van een repository omzet naar UI-state. Het antwoord is `stateIn` (voor één bewaarde waarde) of `shareIn` (voor een broadcast zonder huidige waarde). De parameter `SharingStarted` bepaalt wanneer de upstream actief is, en `WhileSubscribed(5_000)` is de standaardkeuze omdat het de flow in leven houdt tijdens een rotatie zonder deze te lekken wanneer het scherm sluit. ```kotlin // ProfileViewModel.kt val profile: StateFlow = repo.profileStream() .stateIn( scope = viewModelScope, // Keep the upstream alive 5s after the last collector leaves, surviving rotation. started = SharingStarted.WhileSubscribed(5_000), initialValue = Profile.EMPTY ) ``` Het verschil tussen `stateIn` en `shareIn` is precies het verschil tussen StateFlow en SharedFlow: `stateIn` heeft een `initialValue` nodig en houdt state vast, terwijl `shareIn` een `replay`-aantal aanneemt en broadcast. Het bredere coroutinesmodel doornemen in [deze gids om Kotlin-coroutines onder de knie te krijgen](/blog/android/mastering-kotlin-coroutines) helpt om deze operators te koppelen aan scopes en cancellation. ## Flows veilig verzamelen binnen de Android-lifecycle Een vraag op seniorniveau is hoe je een flow verzamelt zonder werk te lekken terwijl het scherm op de achtergrond staat. Verzamelen binnen een gewone `launch` blijft doorlopen wanneer de UI gestopt is, verspilt CPU en riskeert crashes. `repeatOnLifecycle(STARTED)` annuleert het verzamelen bij `STOP` en herstart het bij `START`. ```kotlin // ProfileFragment.kt (View system) viewLifecycleOwner.lifecycleScope.launch { // Collection restarts on STARTED and cancels on STOPPED: no wasted work in the background. viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.uiState.collect { state -> render(state) } } } ``` In Jetpack Compose is `collectAsStateWithLifecycle()` het equivalent, dat stopt met verzamelen wanneer de app naar de achtergrond gaat en hervat bij terugkeer. ```kotlin // ProfileScreen.kt (Jetpack Compose) @Composable fun ProfileScreen(viewModel: ProfileViewModel) { // collectAsStateWithLifecycle stops collecting when the app is backgrounded. val state by viewModel.uiState.collectAsStateWithLifecycle() ProfileContent(state) } ``` Dit lifecyclebewustzijn is de reden dat StateFlow gecombineerd met `collectAsStateWithLifecycle` het standaard state-patroon is in moderne Compose-apps, iets wat verder aan bod komt in deze [Jetpack Compose-interviewvragen](/blog/android/jetpack-compose-interview-questions). ## StateFlow- en SharedFlow-emissies testen Bij testen onderscheiden seniorkandidaten zich. De naïeve aanpak leest `stateFlow.value` één keer uit, maar dat mist tussenliggende states en kan een SharedFlow helemaal niet observeren. Het standaardantwoord noemt de Turbine-library, die suspendt totdat elke emissie binnenkomt en de test laat falen als een verwachte waarde nooit komt. ```kotlin // SearchViewModelTest.kt @Test fun `emits Loading then Success on query`() = runTest { val viewModel = SearchViewModel(fakeRepo) viewModel.uiState.test { assertEquals(SearchUiState.Idle, awaitItem()) // initial value viewModel.onQueryChanged("kotlin") assertEquals(SearchUiState.Loading, awaitItem()) // intermediate state assertEquals(SearchUiState.Success(fakeResults), awaitItem()) cancelAndIgnoreRemainingEvents() } } ``` Turbine combineren met `runTest` en een test dispatcher houdt de assertions deterministisch, en het noemen van `StandardTestDispatcher` versus `UnconfinedTestDispatcher` verraadt echte ervaring met het testen van coroutines. ## Veelvoorkomende vervolgvragen over Kotlin Flow Interviewers sluiten af met snelle controlevragen. Wat doet `SharingStarted.WhileSubscribed(5_000)`? Het start de upstream bij de eerste subscriber en stopt deze 5 seconden nadat de laatste zich afmeldt, lang genoeg om een rotatie te overleven. Waarom slaat StateFlow dubbele waarden over? Het vergelijkt met `equals()`, dus een gelijke waarde uitzenden is een no-op, en juist daarom zijn data classes belangrijk voor state. Kan SharedFlow zich gedragen als StateFlow? `replay = 1` instellen laat het de laatste waarde bewaren, maar het mist nog steeds een synchrone `.value` en ontdubbelt nooit. Wat regelt de back-pressure op een SharedFlow? De parameters `extraBufferCapacity` en `onBufferOverflow`, waarbij `BufferOverflow.DROP_OLDEST` een gangbare keuze is voor events. Meer oefening met deze operators is te vinden in de [interviewmodule over Kotlin-coroutines en Flow](/technologies/android/interview-questions/android-kotlin-coroutines-flow). > **De fout die kandidaten laat zakken** > > `StateFlow` gebruiken voor navigatie- of snackbar-events. Omdat het zijn laatste waarde opnieuw afspeelt naar nieuwe collectors, vuurt het event na een rotatie opnieuw af en wordt de gebruiker twee keer genavigeerd. Grijp naar `SharedFlow` met `replay = 0`, of modelleer een eenmalig event dat na afhandeling wordt gewist. De broncode van kotlinx.coroutines en de [referentie van het flow-package op GitHub](https://github.com/Kotlin/kotlinx.coroutines/tree/master/kotlinx-coroutines-core) zijn het waard om voor een interview door te nemen, aangezien de KDoc bij `StateFlow` en `SharedFlow` de conflatie- en replaygaranties precies beschrijft. ## Conclusie Het onderscheid Kotlin Flow vs StateFlow vs SharedFlow beloont precies taalgebruik in een interview. De belangrijkste punten om mee te nemen: - `Flow` is cold: de producer draait opnieuw voor elke collector, waardoor het past bij datapijplijnen op aanvraag. - `StateFlow` is hot, houdt altijd een waarde vast en conflateert en ontdubbelt, wat het de tool voor UI-state maakt. - `SharedFlow` is hot zonder verplichte beginwaarde, wat het de juiste keuze maakt voor eenmalige events. - Zet cold om naar hot met `stateIn` of `shareIn`, en gebruik `SharingStarted.WhileSubscribed(5_000)` om een rotatie te overleven. - Verzamel met `repeatOnLifecycle(STARTED)` of `collectAsStateWithLifecycle()` om achtergrondwerk en lekken te voorkomen. - Lever events nooit via StateFlow: het replaygedrag vuurt ze opnieuw af na een configuratiewijziging. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/nl/blog/android/kotlin-flow-vs-stateflow-vs-sharedflow-interview