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.

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.
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 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.
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
}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.
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) }
}
}
}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 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.
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)
}
}
}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, 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.
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
)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 ajuda a conectar esses operadores a escopos e cancelamento.
Pronto para mandar bem nas entrevistas de Android?
Pratique com nossos simuladores interativos, flashcards e testes tecnicos.
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.
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.
@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.
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.
@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.
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 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
stateInoushareIn, e useSharingStarted.WhileSubscribed(5_000)para sobreviver à rotação. - Colete com
repeatOnLifecycle(STARTED)oucollectAsStateWithLifecycle()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.
Comece a praticar!
Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.
Tags
Compartilhar
Artigos relacionados

Kotlin 2.3 para Android: Desestruturação por Nome, KMP e Perguntas de Entrevista 2026
Perguntas de entrevista sobre Kotlin 2.3 para desenvolvedores Android em 2026. Desestruturação por nome, KMP, parâmetros de contexto, Flow e coroutines com exemplos de código.

As 20 perguntas mais frequentes sobre Jetpack Compose em entrevistas (2026)
As 20 perguntas de entrevista sobre Jetpack Compose mais comuns: recomposição, gerenciamento de estado, navegação, performance e padrões de arquitetura.

Dominando Kotlin Coroutines: Guia Completo 2026
Aprenda a dominar Kotlin coroutines para desenvolvimento Android: funções suspend, scopes, dispatchers e padrões avançados.