Kotlin Flow vs StateFlow vs SharedFlow: Android-Interviewfragen 2026
Die Fragen zu Kotlin Flow vs StateFlow vs SharedFlow, die Android-Interviewer 2026 stellen – mit klaren Antworten, Vergleichstabelle und produktionsreifem Code.

Kotlin Flow vs StateFlow vs SharedFlow gehört 2026 zu den häufigsten Themen im Android-Interview, und wer die drei durcheinanderbringt, verliert eine Coroutines-Runde schnell. StateFlow und SharedFlow sind beide heiße Streams, die auf Flow aufbauen, doch sie lösen unterschiedliche Probleme: das Halten von Zustand gegenüber dem Verteilen von Events. Die folgenden Fragen stellen Android-Interviewer tatsächlich – mit präzisen Antworten und produktionsreifem Code.
Ein Flow ist kalt und führt seinen Producer einmal pro Collector aus. StateFlow ist ein heißer, konflatierter Stream, der stets einen einzigen aktuellen Wert hält – ideal für UI-Zustand. SharedFlow ist ein heißer Stream ohne erforderlichen Anfangswert, ideal für einmalige Events wie Navigation oder eine Snackbar.
Kotlin Flow vs StateFlow vs SharedFlow: die zentralen Unterschiede
StateFlow und SharedFlow sind Spezialisierungen von SharedFlow, das selbst ein heißer Flow ist. Interviewer prüfen die Unterscheidung kalt gegenüber heiß, ob ein aktueller Wert erhalten bleibt und wie sich jeder Typ bei doppelten Emissionen verhält. Ein knappes mentales Modell: Flow ist ein Rezept, StateFlow ist ein einzelner veränderbarer Wert und SharedFlow ist ein Event-Bus.
| Eigenschaft | Flow (kalt) | StateFlow | SharedFlow |
|---|---|---|---|
| Temperatur | Kalt | Heiß | Heiß |
| Anfangswert | Keiner | Erforderlich | Optional (über replay) |
| Hält aktuellen Wert | Nein | Ja, über .value | Nein |
| Emittiert Duplikate | Ja | Nein (konflatiert + dedupliziert) | Konfigurierbar |
| Weitere Collector | Jedes Mal neuer Stream | Geteilt | Geteilt |
| Am besten für | Asynchrone Datenpipelines | UI-Zustand | Einmalige Events |
Die offizielle Kotlin-Coroutines-Dokumentation behandelt dieses standardmäßig kalte Verhalten als das definierende Merkmal von Flow, weshalb eine starke Antwort genau dort ansetzt.
Warum ist ein Kotlin Flow standardmäßig kalt?
Ein kalter Flow tut nichts, bis collect() aufgerufen wird, und er führt seinen Producer-Block für jeden Collector erneut aus. Zwei Collector auf demselben kalten Flow lösen zwei unabhängige Netzwerkaufrufe aus. Das ist das am häufigsten abgefragte Konzept, weshalb ein kurzes Beispiel die Antwort verankert.
fun searchResults(query: String): Flow<List<Result>> = 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
}Da der Producer pro Collector neu startet, sind kalte Flows die richtige Voreinstellung für Datenpipelines, die bei Bedarf laufen sollen. Zum Problem werden sie erst, wenn ein Wert über einen gesamten Screen hinweg geteilt werden muss – und genau hier kommen StateFlow und SharedFlow ins Spiel.
StateFlow-Interviewfragen: Zustand, der immer emittiert
StateFlow ist ein heißer Flow, der immer einen Wert besitzt und diesen letzten Wert an jeden neuen Collector erneut ausspielt. Er verlangt einen Anfangswert, stellt .value für synchrone Lesezugriffe bereit und konflatiert Emissionen: Schnelle aufeinanderfolgende Updates können Zwischenwerte überspringen, und das zweimalige Setzen desselben Werts emittiert nichts, weil per Gleichheit dedupliziert wird. Das macht ihn zum modernen Ersatz für LiveData in einem ViewModel.
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>(SearchUiState.Idle)
val uiState: StateFlow<SearchUiState> = _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) }
}
}
}Eine häufige Anschlussfrage: Warum asStateFlow() bereitstellen statt des veränderbaren Felds? Es reicht der UI eine schreibgeschützte Sicht, sodass sich der Zustand nur über das ViewModel ändern lässt – das hält den unidirektionalen Datenfluss intakt. Androids eigener Leitfaden zu StateFlow und SharedFlow empfiehlt genau dieses Muster.
SharedFlow vs StateFlow: den richtigen Typ für Events wählen
Die klassische Fangfrage lautet: „Kann StateFlow einmalige Events liefern?“ Die ehrliche Antwort ist nein, nicht zuverlässig. Weil StateFlow konflatiert und dedupliziert, kann ein Navigations-Event bei schnellen Updates verloren gehen, und es feuert bei einer Konfigurationsänderung erneut, weil ein neuer Collector den erhaltenen Wert erneut ausspielt. SharedFlow mit replay = 0 behebt beides: Nichts bleibt erhalten, und jede Emission erreicht nur die zum Emissionszeitpunkt aktiven Collector.
class CheckoutViewModel : ViewModel() {
// replay = 0: a late collector must NOT re-receive a past navigation event.
private val _events = MutableSharedFlow<CheckoutEvent>(replay = 0)
val events: SharedFlow<CheckoutEvent> = _events.asSharedFlow()
fun onPaymentConfirmed() {
viewModelScope.launch {
// emit() suspends if the buffer is full; tryEmit() is the non-suspending variant.
_events.emit(CheckoutEvent.NavigateToReceipt)
}
}
}Bei Architekturfragen zeigt sich die tiefere Begründung für die Trennung von Zustand und Events im Vergleich MVVM vs MVI, wo MVI Events als expliziten Stream statt als veränderbaren Zustand behandelt.
Einen kalten Flow mit stateIn in einen heißen StateFlow umwandeln
Interviewer fragen häufig, wie sich der kalte Flow eines Repositorys in UI-Zustand überführen lässt. Die Antwort lautet stateIn (für einen einzelnen erhaltenen Wert) oder shareIn (für eine Verteilung ohne aktuellen Wert). Der Parameter SharingStarted steuert, wann der Upstream aktiv ist, und WhileSubscribed(5_000) ist die Standardwahl, weil es den Flow über eine Rotation hinweg am Leben hält, aber kein Leck verursacht, wenn der Screen geschlossen wird.
val profile: StateFlow<Profile> = 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
)Der Unterschied zwischen stateIn und shareIn ist genau der Unterschied zwischen StateFlow und SharedFlow: stateIn benötigt einen initialValue und hält Zustand, während shareIn einen replay-Wert entgegennimmt und verteilt. Ein Blick auf das umfassendere Coroutines-Modell in diesem Leitfaden zum Meistern von Kotlin-Coroutines hilft, diese Operatoren mit Scopes und Cancellation zu verbinden.
Bereit für deine Android-Interviews?
Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.
Flows sicher im Android-Lifecycle sammeln
Eine Frage auf Senior-Niveau lautet, wie sich ein Flow sammeln lässt, ohne Arbeit zu verschwenden, während der Screen im Hintergrund liegt. Ein Sammeln in einem einfachen launch läuft weiter, wenn die UI gestoppt ist – das verschwendet CPU und riskiert Abstürze. repeatOnLifecycle(STARTED) bricht die Sammlung bei STOP ab und startet sie bei START neu.
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 ist das Äquivalent collectAsStateWithLifecycle(), das die Sammlung stoppt, wenn die App in den Hintergrund wechselt, und bei der Rückkehr fortsetzt.
@Composable
fun ProfileScreen(viewModel: ProfileViewModel) {
// collectAsStateWithLifecycle stops collecting when the app is backgrounded.
val state by viewModel.uiState.collectAsStateWithLifecycle()
ProfileContent(state)
}Dieses Lifecycle-Bewusstsein ist der Grund, warum StateFlow zusammen mit collectAsStateWithLifecycle das Standard-Zustandsmuster in modernen Compose-Apps ist – ein Punkt, der in diesen Jetpack-Compose-Interviewfragen weiter behandelt wird.
StateFlow- und SharedFlow-Emissionen testen
Beim Testen heben sich Senior-Kandidaten ab. Der naive Ansatz liest stateFlow.value einmal, verpasst dabei aber Zwischenzustände und kann einen SharedFlow gar nicht beobachten. Die Standardantwort nennt die Turbine-Bibliothek, die suspendiert, bis jede Emission eintrifft, und den Test fehlschlagen lässt, wenn ein erwarteter Wert nie kommt.
@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 mit runTest und einem Test-Dispatcher zu kombinieren, hält die Assertions deterministisch, und die Erwähnung von StandardTestDispatcher gegenüber UnconfinedTestDispatcher signalisiert echte Erfahrung im Testen von Coroutines.
Häufige Anschlussfragen zu Kotlin Flow
Interviewer schließen mit schnellen Kurzfragen ab. Was macht SharingStarted.WhileSubscribed(5_000)? Es startet den Upstream beim ersten Abonnenten und stoppt ihn 5 Sekunden, nachdem sich der letzte abgemeldet hat – lang genug, um eine Rotation zu überstehen. Warum überspringt StateFlow doppelte Werte? Er vergleicht mit equals(), weshalb das Emittieren eines gleichen Werts wirkungslos ist – deshalb sind Data-Klassen für Zustand wichtig. Kann sich SharedFlow wie StateFlow verhalten? Mit replay = 1 behält er den letzten Wert, doch ihm fehlt weiterhin ein synchrones .value, und er dedupliziert nie. Was steuert den Back-Pressure eines SharedFlow? Die Parameter extraBufferCapacity und onBufferOverflow, wobei BufferOverflow.DROP_OLDEST eine gängige Wahl für Events ist. Tiefere Übung zu diesen Operatoren findet sich im Interview-Modul zu Kotlin-Coroutines und Flow.
StateFlow für Navigations- oder Snackbar-Events zu verwenden. Weil er seinen letzten Wert an neue Collector erneut ausspielt, feuert das Event nach einer Rotation erneut, und der Nutzer wird zweimal navigiert. Stattdessen SharedFlow mit replay = 0 einsetzen oder ein einmaliges Event modellieren, das nach der Verarbeitung gelöscht wird.
Der Quellcode von kotlinx.coroutines und seine Referenz zum Flow-Paket auf GitHub lohnen vor einem Interview einen Blick, da die KDoc zu StateFlow und SharedFlow die Garantien zu Konflation und Replay präzise beschreibt.
Fazit
Die Unterscheidung Kotlin Flow vs StateFlow vs SharedFlow belohnt im Interview präzise Sprache. Die wichtigsten Erkenntnisse für den Ernstfall:
Flowist kalt: Der Producer läuft für jeden Collector erneut, weshalb er zu bedarfsgesteuerten Datenpipelines passt.StateFlowist heiß, hält stets einen Wert und konflatiert und dedupliziert – das macht ihn zum Werkzeug für UI-Zustand.SharedFlowist heiß und ohne erforderlichen Anfangswert – das macht ihn zur richtigen Wahl für einmalige Events.- Kalt mit
stateInodershareInin heiß umwandeln undSharingStarted.WhileSubscribed(5_000)nutzen, um eine Rotation zu überstehen. - Mit
repeatOnLifecycle(STARTED)odercollectAsStateWithLifecycle()sammeln, um Hintergrundarbeit und Lecks zu vermeiden. - Events nie über StateFlow ausliefern: Sein Replay-Verhalten feuert sie nach einer Konfigurationsänderung erneut.
Fang an zu üben!
Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.
Tags
Teilen
Verwandte Artikel

Kotlin 2.3 im Android-Interview: Namensbasierte Destrukturierung, KMP und Interviewfragen 2026
Kotlin 2.3 Interviewfragen zu namensbasierter Destrukturierung, Kotlin Multiplatform, Kontextparametern, Coroutines und Flow. Vorbereitung auf Android-Entwickler-Interviews 2026 mit praxisnahen Codebeispielen.

Die 20 wichtigsten Jetpack Compose Interviewfragen 2026
Die 20 am häufigsten gestellten Jetpack Compose Interviewfragen: Recomposition, State-Management, Navigation, Performance und Architekturmuster.

Kotlin Coroutines meistern: Vollständiger Guide 2026
Kotlin Coroutines für die Android-Entwicklung meistern: Suspend-Funktionen, Scopes, Dispatcher und fortgeschrittene Patterns.