# Kotlin Flow vs StateFlow vs SharedFlow: perguntas de entrevista Android em 2026 > As perguntas sobre Kotlin Flow vs StateFlow vs SharedFlow que os entrevistadores de Android fazem em 2026, com respostas claras, tabela comparativa e código pronto para produção. - 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 é um dos temas mais recorrentes em entrevistas de Android em 2026, e confundir os três é a maneira mais rápida de perder pontos na rodada de coroutines. StateFlow e SharedFlow são ambos fluxos hot construídos sobre o Flow, mas existem para resolver problemas diferentes: manter estado versus difundir eventos. As perguntas a seguir são as que os entrevistadores de Android realmente fazem, com respostas precisas e código pronto para produção. > **A resposta em 20 segundos** > > Um `Flow` é cold e executa seu produtor uma vez para cada coletor. `StateFlow` é um fluxo hot e conflated que sempre mantém um único valor atual, ideal para estado de UI. `SharedFlow` é um fluxo hot sem valor inicial obrigatório, ideal para eventos únicos como navegação ou um snackbar. ## Kotlin Flow vs StateFlow vs SharedFlow: as diferenças fundamentais StateFlow e SharedFlow são especializações de `SharedFlow`, que por sua vez é um `Flow` hot. A distinção que os entrevistadores investigam é cold versus hot, se um valor atual é retido e como cada um se comporta com emissões duplicadas. Um modelo mental conciso: `Flow` é uma receita, `StateFlow` é um único valor mutável e `SharedFlow` é um barramento de eventos. | Propriedade | Flow (cold) | StateFlow | SharedFlow | |---|---|---|---| | Temperatura | Cold | Hot | Hot | | Valor inicial | Nenhum | Obrigatório | Opcional (via `replay`) | | Mantém valor atual | Não | Sim, via `.value` | Não | | Emite duplicatas | Sim | Não (conflated + deduplicado) | Configurável | | Coletores adicionais | Novo fluxo a cada vez | Compartilhado | Compartilhado | | Melhor para | Pipelines de dados assíncronos | Estado de UI | Eventos únicos | A [documentação oficial de coroutines do Kotlin](https://kotlinlang.org/docs/flow.html) trata esse comportamento cold-by-default como a propriedade que define o `Flow`, então uma boa resposta começa por aí. ## Por que um Kotlin Flow é cold por padrão? Um fluxo cold não faz nada até que `collect()` seja chamado, e reexecuta seu bloco produtor para cada coletor. Dois coletores no mesmo fluxo cold disparam duas chamadas de rede independentes. Esse é o conceito mais cobrado de todos, então um exemplo curto ancora a resposta. ```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 } ``` Como o produtor reinicia a cada coletor, fluxos cold são o padrão certo para pipelines de dados que devem rodar sob demanda. Eles só se tornam um problema quando um valor precisa ser compartilhado por uma tela inteira, que é exatamente onde StateFlow e SharedFlow entram. ## Perguntas de entrevista sobre StateFlow: estado que sempre emite `StateFlow` é um fluxo hot que sempre tem um valor e reproduz esse valor mais recente para cada novo coletor. Ele exige um valor inicial, expõe `.value` para leituras síncronas e faz conflation das emissões: atualizações rápidas e sucessivas podem pular valores intermediários, e definir o mesmo valor duas vezes não emite nada porque ele deduplica por igualdade. Isso o torna o substituto moderno do `LiveData` dentro de um `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) } } } } ``` Um follow-up comum: por que expor `asStateFlow()` em vez do campo mutável? Isso entrega à UI uma visão somente leitura, de modo que o estado só pode mudar através do ViewModel, o que mantém o fluxo de dados unidirecional intacto. O próprio [guia de StateFlow e SharedFlow do Android](https://developer.android.com/kotlin/flow/stateflow-and-sharedflow) recomenda exatamente esse padrão. ## SharedFlow vs StateFlow: escolhendo o tipo certo para eventos A pergunta-armadilha clássica é: "o StateFlow consegue entregar eventos únicos?" A resposta honesta é não, não de forma segura. Como o StateFlow faz conflation e deduplicação, um evento de navegação pode ser descartado sob atualizações rápidas, e ele dispara de novo em uma mudança de configuração porque um novo coletor reproduz o valor retido. `SharedFlow` com `replay = 0` resolve os dois casos: nada é retido, e cada emissão alcança apenas os coletores ativos no momento da emissão. ```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) } } } ``` Para perguntas sobre arquitetura, o raciocínio mais profundo por trás de separar estado de eventos aparece na [comparação entre MVVM e MVI](/blog/android/mvvm-vs-mvi-architecture), em que o MVI trata eventos como um stream explícito em vez de estado mutável. ## Convertendo um Flow cold em um StateFlow hot com stateIn Entrevistadores frequentemente perguntam como transformar o fluxo cold de um repositório em estado de UI. A resposta é `stateIn` (para um único valor retido) ou `shareIn` (para uma difusão sem valor atual). O parâmetro `SharingStarted` controla quando o upstream fica ativo, e `WhileSubscribed(5_000)` é a escolha padrão porque mantém o fluxo vivo durante uma rotação sem vazá-lo quando a tela é fechada. ```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 ) ``` A diferença entre `stateIn` e `shareIn` é exatamente a diferença entre StateFlow e SharedFlow: `stateIn` precisa de um `initialValue` e mantém estado, enquanto `shareIn` recebe uma contagem de `replay` e difunde. Revisar o modelo mais amplo de coroutines [neste guia para dominar as coroutines do Kotlin](/blog/android/mastering-kotlin-coroutines) ajuda a conectar esses operadores a escopos e cancelamento. ## Coletando fluxos com segurança no ciclo de vida do Android Uma pergunta de nível sênior é como coletar um fluxo sem vazar trabalho enquanto a tela está em segundo plano. Coletar dentro de um `launch` comum continua rodando quando a UI está parada, desperdiçando CPU e arriscando crashes. `repeatOnLifecycle(STARTED)` cancela a coleta no `STOP` e a reinicia no `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) } } } ``` No Jetpack Compose o equivalente é `collectAsStateWithLifecycle()`, que para de coletar quando o app vai para segundo plano e retoma ao voltar. ```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) } ``` Essa consciência do ciclo de vida é o motivo pelo qual o StateFlow combinado com `collectAsStateWithLifecycle` é o padrão de estado predominante em apps Compose modernos, um ponto aprofundado nestas [perguntas de entrevista sobre Jetpack Compose](/blog/android/jetpack-compose-interview-questions). ## Como testar emissões de StateFlow e SharedFlow Testes são onde os candidatos sêniores se destacam. A abordagem ingênua lê `stateFlow.value` uma única vez, mas isso perde estados intermediários e não consegue observar um SharedFlow de forma alguma. A resposta padrão cita a biblioteca Turbine, que suspende até cada emissão chegar e falha o teste se um valor esperado nunca vier. ```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() } } ``` Combinar o Turbine com `runTest` e um test dispatcher mantém as asserções determinísticas, e mencionar `StandardTestDispatcher` versus `UnconfinedTestDispatcher` demonstra experiência real em testes de coroutines. ## Follow-ups comuns em entrevistas sobre Kotlin Flow Entrevistadores encerram com perguntas rápidas. O que `SharingStarted.WhileSubscribed(5_000)` faz? Ele inicia o upstream no primeiro inscrito e o para 5 segundos depois que o último cancela a inscrição, tempo suficiente para sobreviver a uma rotação. Por que o StateFlow ignora valores duplicados? Ele compara com `equals()`, então emitir um valor igual é um no-op, e é por isso que data classes importam para o estado. O SharedFlow pode se comportar como StateFlow? Definir `replay = 1` faz com que ele retenha o último valor, mas ele ainda não tem um `.value` síncrono e nunca deduplica. O que controla o back-pressure em um SharedFlow? Os parâmetros `extraBufferCapacity` e `onBufferOverflow`, sendo `BufferOverflow.DROP_OLDEST` uma escolha comum para eventos. Prática mais aprofundada nesses operadores está no [módulo de entrevista sobre coroutines e Flow do Kotlin](/technologies/android/interview-questions/android-kotlin-coroutines-flow). > **O erro que reprova candidatos** > > Usar `StateFlow` para eventos de navegação ou snackbar. Como ele reproduz seu último valor para novos coletores, o evento dispara de novo após uma rotação e o usuário é navegado duas vezes. Recorra ao `SharedFlow` com `replay = 0`, ou modele um evento único que é limpo após ser tratado. Vale a pena dar uma olhada no código-fonte do kotlinx.coroutines e na sua [referência do pacote flow no GitHub](https://github.com/Kotlin/kotlinx.coroutines/tree/master/kotlinx-coroutines-core) antes de uma entrevista, já que o KDoc de `StateFlow` e `SharedFlow` descreve as garantias de conflation e replay com precisão. ## Conclusão A distinção entre Kotlin Flow vs StateFlow vs SharedFlow recompensa uma linguagem precisa em uma entrevista. Pontos-chave para levar: - `Flow` é cold: o produtor roda novamente para cada coletor, então serve para pipelines de dados sob demanda. - `StateFlow` é hot, sempre mantém um valor e faz conflation e deduplicação, o que o torna a ferramenta para estado de UI. - `SharedFlow` é hot e não exige valor inicial, o que o torna a escolha correta para eventos únicos. - Converta cold em hot com `stateIn` ou `shareIn`, e use `SharingStarted.WhileSubscribed(5_000)` para sobreviver à rotação. - Colete com `repeatOnLifecycle(STARTED)` ou `collectAsStateWithLifecycle()` para evitar trabalho em segundo plano e vazamentos. - Nunca entregue eventos através do StateFlow: seu comportamento de replay os dispara de novo após uma mudança de configuração. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pt/blog/android/kotlin-flow-vs-stateflow-vs-sharedflow-interview