Kotlin Flow, StateFlow ve SharedFlow: 2026'da Android Mülakat Soruları

Android mülakatçılarının 2026'da sorduğu Kotlin Flow, StateFlow ve SharedFlow soruları; net yanıtlar, bir karşılaştırma tablosu ve üretime hazır kod ile birlikte.

Android mülakatları için Kotlin Flow, StateFlow ve SharedFlow karşılaştırması

Kotlin Flow, StateFlow ve SharedFlow, 2026'da Android mülakatlarının en sık karşılaşılan konularından biridir ve üçünü birbirine karıştırmak, bir coroutine turunu kaybetmenin en hızlı yoludur. StateFlow ve SharedFlow, Flow üzerine inşa edilmiş sıcak (hot) akışlardır, ancak farklı problemleri çözmek için vardır: durum tutmak ile olay yayınlamak. Aşağıdaki sorular, Android mülakatçılarının gerçekten sorduğu sorulardır; kesin yanıtlar ve üretime hazır kod ile birlikte sunulmuştur.

20 saniyelik yanıt

Bir Flow soğuktur (cold) ve üreticisini her collector için bir kez çalıştırır. StateFlow ise sıcak, birleştirilmiş (conflated) bir akıştır ve her zaman tek bir güncel değer tutar; UI durumu için idealdir. SharedFlow, zorunlu bir başlangıç değeri olmayan sıcak bir akıştır ve navigasyon ya da snackbar gibi tek seferlik olaylar için idealdir.

Kotlin Flow, StateFlow ve SharedFlow: temel farklar

StateFlow ve SharedFlow, kendisi de sıcak bir Flow olan SharedFlow'un özelleşmiş halleridir. Mülakatçıların araştırdığı ayrım şudur: akış soğuk mu sıcak mı, güncel bir değer saklanıyor mu ve her biri yinelenen yayınlarda (duplicate emissions) nasıl davranıyor. Kısa bir zihinsel model: Flow bir tariftir, StateFlow tek bir değiştirilebilir değerdir ve SharedFlow bir olay veri yoludur (event bus).

| Özellik | Flow (soğuk) | StateFlow | SharedFlow | |---|---|---|---| | Sıcaklık | Soğuk | Sıcak | Sıcak | | Başlangıç değeri | Yok | Zorunlu | İsteğe bağlı (replay ile) | | Güncel değeri tutar | Hayır | Evet, .value ile | Hayır | | Yinelenenleri yayınlar | Evet | Hayır (birleştirilir + tekilleştirilir) | Yapılandırılabilir | | Ek collector'lar | Her seferinde yeni akış | Paylaşımlı | Paylaşımlı | | En uygun | Asenkron veri hatları | UI durumu | Tek seferlik olaylar |

Resmi Kotlin coroutines dokümantasyonu, bu varsayılan olarak soğuk olma davranışını Flow'un tanımlayıcı özelliği olarak ele alır; bu yüzden güçlü bir yanıt buradan başlar.

Bir Kotlin Flow neden varsayılan olarak soğuktur?

Soğuk bir flow, collect() çağrılana kadar hiçbir şey yapmaz ve üretici bloğunu her collector için yeniden çalıştırır. Aynı soğuk flow üzerindeki iki collector, iki bağımsız ağ çağrısını tetikler. Bu, en çok test edilen tek kavramdır; bu yüzden kısa bir örnek yanıtı sağlamlaştırır.

SearchRepository.ktkotlin
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
}

Üretici her collector için yeniden başladığından, soğuk flow'lar talep üzerine çalışması gereken veri hatları için doğru varsayılandır. Yalnızca bir değerin tüm ekran boyunca paylaşılması gerektiğinde sorun haline gelirler; tam da StateFlow ile SharedFlow'un devreye girdiği nokta budur.

StateFlow mülakat soruları: her zaman yayın yapan durum

StateFlow, her zaman bir değere sahip olan ve bu en son değeri her yeni collector'a yeniden gönderen (replay) sıcak bir flow'dur. Bir başlangıç değeri gerektirir, senkron okumalar için .value sunar ve yayınları birleştirir (conflate): hızlı ardışık güncellemeler ara değerleri atlayabilir ve aynı değeri iki kez atamak hiçbir şey yayınlamaz, çünkü eşitlik (equality) üzerinden tekilleştirme yapar. Bu da onu bir ViewModel içindeki LiveData'nın modern alternatifi haline getirir.

SearchViewModel.ktkotlin
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) }
        }
    }
}

Sık gelen bir devam sorusu: neden değiştirilebilir alan yerine asStateFlow() açığa çıkarılır? Bu, UI'a yalnızca okunabilir bir görünüm verir; böylece durum yalnızca ViewModel üzerinden değişebilir ve tek yönlü veri akışı bozulmadan korunur. Android'in kendi StateFlow ve SharedFlow rehberi tam olarak bu deseni önerir.

SharedFlow vs StateFlow: olaylar için doğru türü seçmek

Klasik tuzak soru şudur: "StateFlow tek seferlik olaylar iletebilir mi?" Dürüst yanıt hayırdır, en azından güvenli bir şekilde iletemez. StateFlow birleştirdiği ve tekilleştirdiği için, bir navigasyon olayı hızlı güncellemeler altında düşürülebilir; ayrıca yapılandırma değişikliğinde yeniden tetiklenir, çünkü yeni bir collector saklanan değeri yeniden gönderir. replay = 0 ile SharedFlow her ikisini de çözer: hiçbir şey saklanmaz ve her yayın yalnızca yayın anında aktif olan collector'lara ulaşır.

CheckoutViewModel.ktkotlin
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)
        }
    }
}

Mimari sorularında, durumu olaylardan ayırmanın ardındaki daha derin gerekçe MVVM vs MVI karşılaştırmasında ortaya çıkar; burada MVI, olayları değiştirilebilir durum yerine açık bir akış olarak ele alır.

stateIn ile soğuk bir Flow'u sıcak bir StateFlow'a dönüştürmek

Mülakatçılar sıklıkla bir repository'nin soğuk flow'unun UI durumuna nasıl dönüştürüleceğini sorar. Yanıt, stateIn (tek bir saklanan değer için) veya shareIn (güncel değeri olmayan bir yayın için) kullanmaktır. SharingStarted parametresi upstream'in ne zaman aktif olacağını denetler ve WhileSubscribed(5_000) standart seçimdir, çünkü flow'u bir ekran döndürme boyunca canlı tutarken ekran kapandığında sızdırmaz.

ProfileViewModel.ktkotlin
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
    )

stateIn ile shareIn arasındaki fark, tam olarak StateFlow ile SharedFlow arasındaki farktır: stateIn bir initialValue gerektirir ve durum tutar, shareIn ise bir replay sayısı alır ve yayın yapar. Daha geniş coroutine modelini Kotlin coroutine'lerinde ustalaşma rehberinde gözden geçirmek, bu operatörleri kapsamlar (scope) ve iptal (cancellation) ile ilişkilendirmeye yardımcı olur.

Android mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

Android yaşam döngüsünde flow'ları güvenli şekilde toplamak

Kıdemli seviye bir soru, ekran arka plandayken işi sızdırmadan bir flow'un nasıl toplanacağıdır. Düz bir launch içinde toplama yapmak, UI durdurulduğunda çalışmaya devam eder; bu da CPU'yu boşa harcar ve çökme riski yaratır. repeatOnLifecycle(STARTED), toplamayı STOP anında iptal eder ve START anında yeniden başlatır.

ProfileFragment.kt (View system)kotlin
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) }
    }
}

Jetpack Compose'da bunun karşılığı collectAsStateWithLifecycle()'dır; uygulama arka plana alındığında toplamayı durdurur ve geri dönüldüğünde devam ettirir.

ProfileScreen.kt (Jetpack Compose)kotlin
@Composable
fun ProfileScreen(viewModel: ProfileViewModel) {
    // collectAsStateWithLifecycle stops collecting when the app is backgrounded.
    val state by viewModel.uiState.collectAsStateWithLifecycle()
    ProfileContent(state)
}

Bu yaşam döngüsü farkındalığı, collectAsStateWithLifecycle ile eşleştirilmiş StateFlow'un modern Compose uygulamalarında neden varsayılan durum deseni olduğunu açıklar; bu konu şu Jetpack Compose mülakat sorularında daha ayrıntılı ele alınır.

StateFlow ve SharedFlow yayınları nasıl test edilir

Kıdemli adaylar kendilerini test yazımında ayrıştırır. Naif yaklaşım stateFlow.value'yu bir kez okur, ancak bu ara durumları kaçırır ve bir SharedFlow'u hiç gözlemleyemez. Standart yanıt, her yayın gelene kadar bekleyen (suspend eden) ve beklenen bir değer hiç gelmezse testi başarısız kılan Turbine kütüphanesini anar.

SearchViewModelTest.ktkotlin
@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'i runTest ve bir test dispatcher'ı ile birleştirmek, doğrulamaları belirlenimci (deterministic) tutar; StandardTestDispatcher ile UnconfinedTestDispatcher arasındaki farktan söz etmek ise gerçek coroutine test deneyimini gösterir.

Sık gelen Kotlin Flow mülakat devam soruları

Mülakatçılar seri sorularla kapanış yapar. SharingStarted.WhileSubscribed(5_000) ne yapar? Upstream'i ilk aboneyle başlatır ve son abone ayrıldıktan 5 saniye sonra durdurur; bu süre bir ekran döndürmeyi atlatmaya yetecek kadar uzundur. StateFlow neden yinelenen değerleri atlar? equals() ile karşılaştırma yapar, dolayısıyla eşit bir değer yayınlamak işlemsizdir (no-op); durum için data class'ların önemli olmasının nedeni budur. SharedFlow, StateFlow gibi davranabilir mi? replay = 1 ayarlamak son değeri tutmasını sağlar, ancak yine de senkron bir .value'dan yoksundur ve asla tekilleştirme yapmaz. SharedFlow üzerindeki geri baskıyı (back-pressure) ne denetler? extraBufferCapacity ve onBufferOverflow parametreleri; olaylar için BufferOverflow.DROP_OLDEST sık tercih edilen bir seçenektir. Bu operatörler üzerinde daha derin pratik, Kotlin coroutines ve Flow mülakat modülünde yer alır.

Adayları eleyen hata

Navigasyon veya snackbar olayları için StateFlow kullanmak. Son değerini yeni collector'lara yeniden gönderdiği için, olay bir ekran döndürmeden sonra yeniden tetiklenir ve kullanıcı iki kez yönlendirilir. Bunun yerine replay = 0 ile SharedFlow tercih edilmeli ya da işlendikten sonra temizlenen tek seferlik bir olay modellenmelidir.

kotlinx.coroutines kaynak kodu ve onun GitHub'daki flow paketi referansı bir mülakattan önce göz atmaya değer, çünkü StateFlow ve SharedFlow üzerindeki KDoc, birleştirme (conflation) ve replay garantilerini tam olarak belirtir.

Sonuç

Kotlin Flow, StateFlow ve SharedFlow ayrımı, bir mülakatta kesin dili ödüllendirir. Bir mülakata taşınabilecek temel çıkarımlar:

  • Flow soğuktur: üretici her collector için yeniden çalışır, bu yüzden talep üzerine çalışan veri hatlarına uygundur.
  • StateFlow sıcaktır, her zaman bir değer tutar ve hem birleştirir hem tekilleştirir; bu da onu UI durumu için doğru araç yapar.
  • SharedFlow sıcaktır ve zorunlu bir başlangıç değeri yoktur; bu da onu tek seferlik olaylar için doğru seçim yapar.
  • Soğuktan sıcağa geçiş stateIn ya da shareIn ile yapılır ve rotasyonu atlatmak için SharingStarted.WhileSubscribed(5_000) kullanılır.
  • Arka plan işini ve sızıntıları önlemek için toplama repeatOnLifecycle(STARTED) ya da collectAsStateWithLifecycle() ile yapılır.
  • Olaylar asla StateFlow üzerinden iletilmemelidir: replay davranışı, bir yapılandırma değişikliğinden sonra onları yeniden tetikler.

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Etiketler

#android
#kotlin
#coroutines
#flow
#interview

Paylaş

İlgili makaleler