# Kotlin Flow vs StateFlow vs SharedFlow: Pertanyaan Interview Android 2026 > Pertanyaan Kotlin Flow vs StateFlow vs SharedFlow yang diajukan pewawancara Android pada 2026, dengan jawaban jelas, tabel perbandingan, dan kode siap produksi. - 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 merupakan salah satu topik interview Android yang paling sering muncul pada 2026, dan mencampuradukkan ketiganya adalah cara tercepat untuk gagal di sesi coroutines. StateFlow dan SharedFlow sama-sama merupakan hot stream yang dibangun di atas Flow, tetapi keduanya hadir untuk menyelesaikan masalah yang berbeda: menyimpan state versus menyiarkan event. Pertanyaan-pertanyaan berikut adalah yang benar-benar diajukan pewawancara Android, lengkap dengan jawaban yang tepat serta kode siap produksi. > **Jawaban 20 detik** > > Sebuah `Flow` bersifat cold dan menjalankan produsernya sekali untuk setiap collector. `StateFlow` adalah stream hot yang di-conflate dan selalu menyimpan satu nilai terkini, ideal untuk UI state. `SharedFlow` adalah stream hot tanpa nilai awal wajib, ideal untuk event sekali pakai seperti navigasi atau snackbar. ## Kotlin Flow vs StateFlow vs SharedFlow: perbedaan utama StateFlow dan SharedFlow adalah spesialisasi dari `SharedFlow`, yang pada dirinya sendiri merupakan `Flow` yang hot. Perbedaan yang biasa digali pewawancara adalah cold versus hot, apakah nilai terkini dipertahankan, dan bagaimana masing-masing berperilaku terhadap emisi duplikat. Model mental yang ringkas: `Flow` adalah resep, `StateFlow` adalah satu nilai mutable, dan `SharedFlow` adalah event bus. | Properti | Flow (cold) | StateFlow | SharedFlow | |---|---|---|---| | Temperatur | Cold | Hot | Hot | | Nilai awal | Tidak ada | Wajib | Opsional (via `replay`) | | Menyimpan nilai terkini | Tidak | Ya, via `.value` | Tidak | | Memancarkan duplikat | Ya | Tidak (conflated + dedup) | Dapat dikonfigurasi | | Collector tambahan | Stream baru setiap kali | Dibagikan | Dibagikan | | Paling cocok untuk | Pipeline data async | UI state | Event sekali pakai | [Dokumentasi resmi Kotlin coroutines](https://kotlinlang.org/docs/flow.html) memperlakukan perilaku cold-by-default ini sebagai properti yang mendefinisikan `Flow`, sehingga jawaban yang kuat dimulai dari sana. ## Mengapa Kotlin Flow bersifat cold secara default? Sebuah cold flow tidak melakukan apa pun sampai `collect()` dipanggil, dan ia mengeksekusi ulang blok produsernya untuk setiap collector. Dua collector pada cold flow yang sama memicu dua panggilan jaringan yang independen. Ini adalah konsep yang paling sering diuji, sehingga sebuah contoh singkat memperkuat jawaban. ```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 } ``` Karena produser dijalankan ulang untuk setiap collector, cold flow adalah default yang tepat untuk pipeline data yang seharusnya berjalan sesuai permintaan. Ini baru menjadi masalah ketika sebuah nilai harus dibagikan ke seluruh layar, dan di titik itulah StateFlow serta SharedFlow berperan. ## Pertanyaan interview StateFlow: state yang selalu memancarkan nilai `StateFlow` adalah flow hot yang selalu memiliki nilai dan memutar ulang (replay) nilai terbaru tersebut ke setiap collector baru. Ia membutuhkan nilai awal, mengekspos `.value` untuk pembacaan sinkron, serta meng-conflate emisi: pembaruan cepat yang beruntun bisa melewatkan nilai-nilai antara, dan menyetel nilai yang sama dua kali tidak memancarkan apa pun karena StateFlow melakukan deduplikasi melalui kesetaraan (equality). Hal ini menjadikannya pengganti modern untuk `LiveData` di dalam sebuah `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) } } } } ``` Pertanyaan lanjutan yang umum: mengapa mengekspos `asStateFlow()` alih-alih field mutable? Karena ia memberikan UI sebuah tampilan read-only sehingga state hanya bisa berubah melalui ViewModel, yang menjaga unidirectional data flow tetap utuh. [Panduan StateFlow dan SharedFlow](https://developer.android.com/kotlin/flow/stateflow-and-sharedflow) dari Android sendiri merekomendasikan pola persis seperti ini. ## SharedFlow vs StateFlow: memilih tipe yang tepat untuk event Pertanyaan jebakan klasiknya adalah "apakah StateFlow bisa mengirimkan event sekali pakai?" Jawaban jujurnya tidak, tidak dengan aman. Karena StateFlow meng-conflate dan melakukan deduplikasi, sebuah event navigasi bisa hilang saat terjadi pembaruan cepat, dan ia terpicu ulang saat configuration change karena collector baru memutar ulang nilai yang tersimpan. `SharedFlow` dengan `replay = 0` mengatasi keduanya: tidak ada yang disimpan, dan setiap emisi hanya menjangkau collector yang aktif pada saat emisi. ```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) } } } ``` Untuk pertanyaan seputar arsitektur, alasan yang lebih mendalam di balik pemisahan state dari event muncul dalam [perbandingan MVVM vs MVI](/blog/android/mvvm-vs-mvi-architecture), di mana MVI memperlakukan event sebagai stream eksplisit alih-alih mutable state. ## Mengubah cold Flow menjadi hot StateFlow dengan stateIn Pewawancara sering menanyakan cara mengubah cold flow dari sebuah repository menjadi UI state. Jawabannya adalah `stateIn` (untuk satu nilai yang dipertahankan) atau `shareIn` (untuk broadcast tanpa nilai terkini). Parameter `SharingStarted` mengontrol kapan upstream aktif, dan `WhileSubscribed(5_000)` adalah pilihan standar karena ia menjaga flow tetap hidup saat rotasi tanpa membiarkannya bocor ketika layar ditutup. ```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 ) ``` Perbedaan antara `stateIn` dan `shareIn` persis sama dengan perbedaan antara StateFlow dan SharedFlow: `stateIn` membutuhkan `initialValue` dan menyimpan state, sedangkan `shareIn` menerima jumlah `replay` dan melakukan broadcast. Meninjau model coroutines yang lebih luas dalam [panduan menguasai Kotlin coroutines ini](/blog/android/mastering-kotlin-coroutines) membantu menghubungkan operator-operator ini dengan scope dan cancellation. ## Meng-collect flow dengan aman pada lifecycle Android Pertanyaan tingkat senior adalah bagaimana meng-collect sebuah flow tanpa membocorkan pekerjaan ketika layar berada di background. Meng-collect di dalam `launch` biasa akan terus berjalan saat UI dihentikan, memboroskan CPU dan berisiko menyebabkan crash. `repeatOnLifecycle(STARTED)` membatalkan collection pada `STOP` dan menjalankannya kembali pada `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) } } } ``` Di Jetpack Compose, padanannya adalah `collectAsStateWithLifecycle()`, yang berhenti meng-collect ketika aplikasi berada di background dan melanjutkannya kembali saat kembali ke depan. ```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) } ``` Kesadaran terhadap lifecycle inilah yang membuat StateFlow yang dipasangkan dengan `collectAsStateWithLifecycle` menjadi pola state default pada aplikasi Compose modern, sebuah poin yang dibahas lebih lanjut dalam [pertanyaan interview Jetpack Compose ini](/blog/android/jetpack-compose-interview-questions). ## Cara menguji emisi StateFlow dan SharedFlow Pengujian adalah tempat kandidat senior menunjukkan perbedaannya. Pendekatan naif membaca `stateFlow.value` sekali saja, tetapi cara itu melewatkan state antara dan sama sekali tidak dapat mengamati SharedFlow. Jawaban standarnya menyebut library Turbine, yang menunda (suspend) hingga setiap emisi tiba dan menggagalkan tes jika nilai yang diharapkan tidak pernah muncul. ```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() } } ``` Memasangkan Turbine dengan `runTest` dan sebuah test dispatcher menjaga assertion tetap deterministik, dan menyebut `StandardTestDispatcher` versus `UnconfinedTestDispatcher` menandakan pengalaman nyata dalam menguji coroutine. ## Pertanyaan lanjutan interview Kotlin Flow yang umum Pewawancara menutup dengan serangkaian pertanyaan cepat. Apa yang dilakukan `SharingStarted.WhileSubscribed(5_000)`? Ia memulai upstream saat subscriber pertama muncul dan menghentikannya 5 detik setelah subscriber terakhir berhenti, yang cukup lama untuk bertahan melewati rotasi. Mengapa StateFlow melewatkan nilai duplikat? Ia membandingkan dengan `equals()`, sehingga memancarkan nilai yang setara menjadi no-op, dan itulah alasan data class penting untuk state. Apakah SharedFlow bisa berperilaku seperti StateFlow? Menyetel `replay = 1` membuatnya menahan nilai terakhir, tetapi ia tetap tidak memiliki `.value` yang sinkron dan tidak pernah melakukan deduplikasi. Apa yang mengontrol back-pressure pada SharedFlow? Parameter `extraBufferCapacity` dan `onBufferOverflow`, dengan `BufferOverflow.DROP_OLDEST` sebagai pilihan umum untuk event. Latihan yang lebih mendalam tentang operator-operator ini tersedia dalam [modul interview Kotlin coroutines dan Flow](/technologies/android/interview-questions/android-kotlin-coroutines-flow). > **Kesalahan yang menggagalkan kandidat** > > Menggunakan `StateFlow` untuk event navigasi atau snackbar. Karena ia memutar ulang nilai terakhirnya ke collector baru, event tersebut terpicu ulang setelah rotasi dan pengguna dinavigasikan dua kali. Gunakan `SharedFlow` dengan `replay = 0`, atau modelkan sebuah event sekali pakai yang dibersihkan setelah ditangani. Kode sumber kotlinx.coroutines beserta [referensi paket flow-nya di GitHub](https://github.com/Kotlin/kotlinx.coroutines/tree/master/kotlinx-coroutines-core) layak dibaca sekilas sebelum interview, karena KDoc pada `StateFlow` dan `SharedFlow` menyatakan jaminan conflation dan replay secara tepat. ## Kesimpulan Perbedaan antara Kotlin Flow vs StateFlow vs SharedFlow menghargai penggunaan bahasa yang tepat saat interview. Poin-poin utama yang perlu dibawa: - `Flow` bersifat cold: produser dijalankan ulang untuk setiap collector, sehingga cocok untuk pipeline data sesuai permintaan. - `StateFlow` bersifat hot, selalu menyimpan nilai, serta meng-conflate dan melakukan deduplikasi, menjadikannya alat untuk UI state. - `SharedFlow` bersifat hot tanpa nilai awal wajib, menjadikannya pilihan yang tepat untuk event sekali pakai. - Ubah cold menjadi hot dengan `stateIn` atau `shareIn`, dan gunakan `SharingStarted.WhileSubscribed(5_000)` agar bertahan melewati rotasi. - Collect dengan `repeatOnLifecycle(STARTED)` atau `collectAsStateWithLifecycle()` untuk menghindari pekerjaan di background dan kebocoran. - Jangan pernah mengirimkan event melalui StateFlow: perilaku replay-nya akan memicunya ulang setelah configuration change. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/id/blog/android/kotlin-flow-vs-stateflow-vs-sharedflow-interview