Convertendo Flow frio em ativo com shareIn e stateIn
Transforme Flows frios em fluxos ativos com operadores de compartilhamento.
Convertendo Flow frio em ativo com shareIn e stateIn é uma aula grátis de Kotlin Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Kotlin Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Kotlin Academy inclui 4 aulas no total.
Fluxos frios e quentes
Fluxos frios são reiniciados para cada coletor; fluxos quentes compartilham uma única assinatura do fluxo de origem. Converter um fluxo frio em quente evita trabalho redundante quando vários coletores se inscrevem.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun expensiveFlow() = flow {
println("Starting upstream work") // runs once if shared
repeat(3) { delay(100); emit(it) }
}
fun main() = runBlocking {
val cold = expensiveFlow()
// Two collectors = two executions:
launch { cold.collect { } }
launch { cold.collect { } }
delay(500)
coroutineContext.cancelChildren()
}Noções básicas de shareIn
flow.shareIn(scope, started, replay) converte um Flow frio em um SharedFlow, compartilhando uma única assinatura do fluxo de origem.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val cold = flow {
println("Upstream started once")
repeat(5) { delay(100); emit(it) }
}
val hot = cold.shareIn(this, SharingStarted.Eagerly, replay = 0)
launch { hot.collect { println("A: $it") } }
launch { hot.collect { println("B: $it") } }
delay(600)
coroutineContext.cancelChildren()
}Noções básicas de stateIn
flow.stateIn(scope, started, initialValue) converte o fluxo em um StateFlow — que sempre tem um valor e repete 1 valor.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val cold = flow { delay(100); emit(42) }
val state: StateFlow<Int> = cold.stateIn(
scope = this,
started = SharingStarted.Eagerly,
initialValue = 0
)
println(state.value) // 0 immediately
delay(200)
println(state.value) // 42 after upstream emits
coroutineContext.cancelChildren()
}SharingStarted.Eagerly
Eagerly: o fluxo de origem é iniciado imediatamente quando shareIn/stateIn é chamado, independentemente dos assinantes.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val flow = flow {
println("Eagerly started")
emit(1)
}.shareIn(this, SharingStarted.Eagerly)
// Upstream already running even before any collect
delay(50)
launch { flow.collect { println(it) } }
delay(100)
coroutineContext.cancelChildren()
}SharingStarted.Lazily
Lazily: o fluxo de origem é iniciado com o primeiro assinante e nunca é interrompido, mesmo quando o número de assinantes chega a zero.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val flow = flow {
println("Lazily started on first subscriber")
repeat(3) { delay(100); emit(it) }
}.shareIn(this, SharingStarted.Lazily, replay = 1)
delay(50) // no subscriber yet — not started
launch { flow.collect { println(it) } } // triggers start
delay(400)
coroutineContext.cancelChildren()
}SharingStarted.WhileSubscribed
WhileSubscribed(stopTimeout): o fluxo de origem é iniciado quando o primeiro assinante entra e é interrompido stopTimeout milissegundos depois que o último assinante sai. É perfeito para ViewModels.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val flow = flow {
println("Started")
repeat(10) { delay(100); emit(it) }
}.shareIn(this, SharingStarted.WhileSubscribed(500))
val job = launch { flow.collect { print("$it ") } }
delay(300)
job.cancel() // subscriber left
delay(200) // within 500ms stop timeout — still running
launch { flow.collect { print("resume $it ") } }
delay(500)
coroutineContext.cancelChildren()
}Padrão típico de ViewModel
Em ViewModels do Android, converta os fluxos do repositório com stateIn(viewModelScope, WhileSubscribed(5000), initialValue) para compartilhá-los e mantê-los durante alterações de configuração.
import kotlinx.coroutines.flow.*
// In ViewModel:
// val uiState: StateFlow<UiState> = repository
// .dataFlow()
// .map { UiState.Success(it) }
// .stateIn(
// scope = viewModelScope,
// started = SharingStarted.WhileSubscribed(5_000),
// initialValue = UiState.Loading
// )
fun main() { println("WhileSubscribed(5000) is the recommended ViewModel pattern") }shareIn versus stateIn
shareIn → SharedFlow (sem valor atual e com repetição configurável). stateIn → StateFlow (sempre tem um valor e repete 1 valor). Escolha com base na necessidade de os consumidores terem um estado atual.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val cold = (1..3).asFlow().map { it * 10 }
// SharedFlow — no initial value:
val shared: SharedFlow<Int> = cold.shareIn(this, SharingStarted.Eagerly, replay = 1)
// StateFlow — always has a value:
val state: StateFlow<Int> = cold.stateIn(this, SharingStarted.Eagerly, 0)
delay(100)
println("shared cache: ${shared.replayCache}")
println("state value: ${state.value}")
coroutineContext.cancelChildren()
}Compromissos do cache de repetição
Uma repetição maior permite que assinantes tardios vejam mais histórico, mas usa mais memória. Para o estado da interface, replay=1 (stateIn) é suficiente. Para registros de eventos, talvez seja necessária uma repetição maior.
import kotlinx.coroutines.flow.*
// replay=0: no history, only future events
// replay=1: last value (equivalent to stateIn)
// replay=N: last N events — use for message feeds, logs
// Trade-off: memory vs subscriber freshness
fun main() { println("Choose replay based on late-subscriber requirements") }Risco de fluxo não compartilhado
Sem compartilhamento, cada coletor do Compose ou observador do ViewModel executa novamente o fluxo de origem — fazendo chamadas de rede e consultas ao banco de dados redundantes. Sempre compartilhe fluxos caros.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun expensiveApi() = flow {
println("API CALL") // without sharing: once per collector
emit("data")
}
fun main() = runBlocking {
val shared = expensiveApi().shareIn(this, SharingStarted.Lazily, replay = 1)
launch { shared.collect { } } // one API call, shared
launch { shared.collect { } } // same emission
delay(200)
coroutineContext.cancelChildren()
}Limpeza de recursos durante o compartilhamento
Quando o escopo do fluxo compartilhado é cancelado, o fluxo de origem é cancelado e seus blocos finally são executados — os recursos são liberados corretamente.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun resourceFlow() = flow {
try { repeat(10) { delay(100); emit(it) } }
finally { println("Upstream cleaned up") }
}
fun main() = runBlocking {
val scope = CoroutineScope(SupervisorJob())
val shared = resourceFlow().shareIn(scope, SharingStarted.Eagerly)
launch { shared.collect { print("$it ") } }
delay(250)
scope.cancel() // upstream cleanup runs
delay(100)
}Verificação rápida
Qual estratégia de SharingStarted é recomendada para ViewModels do Android?
Recapitulação
shareIn converte para SharedFlow; stateIn converte para StateFlow. Use WhileSubscribed em ViewModels para economizar recursos. O compartilhamento evita execuções redundantes do fluxo de origem quando vários coletores se inscrevem.
Perguntas Frequentes
A aula “Convertendo Flow frio em ativo com shareIn e stateIn” é grátis?
Sim — o texto completo de “Convertendo Flow frio em ativo com shareIn e stateIn” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Kotlin Academy, atualize para CoddyKit PRO. O curso de Kotlin Academy inclui 4 aulas no total.
O que vou aprender em “Convertendo Flow frio em ativo com shareIn e stateIn”?
Transforme Flows frios em fluxos ativos com operadores de compartilhamento. Você pratica Kotlin Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Kotlin Academy?
Nenhuma experiência prévia é necessária. Kotlin Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.
Quanto tempo leva a aula “Convertendo Flow frio em ativo com shareIn e stateIn”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Kotlin Academy?
Sim. Cada aula de Kotlin Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- StateFlow: contêiner de estado ativo para a interface
- SharedFlow: barramentos de eventos e eventos de disparo único
- Convertendo Flow frio em ativo com shareIn e stateIn
- Testando StateFlow e SharedFlow com Turbine