0Pricing
Kotlin Academy · Aula

StateFlow: contêiner de estado ativo para a interface

Use StateFlow como contêiner reativo de estado e observe-o em ViewModels.

StateFlow: contêiner de estado ativo para a interface é uma aula grátis de Kotlin Academy no CoddyKit. Esta é a aula 1 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.

O Que é StateFlow

StateFlow é um fluxo quente que mantém estado, sempre tem um valor e emite atualizações para todos os coletores. Ele substitui o LiveData nas arquiteturas modernas do Kotlin.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val stateFlow = MutableStateFlow(0)  // initial value
    println("Current: ${stateFlow.value}")
    stateFlow.value = 42
    println("Updated: ${stateFlow.value}")
}

MutableStateFlow versus StateFlow

MutableStateFlow é a implementação mutável usada internamente. Exponha StateFlow (somente leitura) para observadores externos fazendo uma conversão de tipo ou usando .asStateFlow().

import kotlinx.coroutines.flow.*
class CounterViewModel {
    private val _count = MutableStateFlow(0)  // mutable internally
    val count: StateFlow<Int> = _count.asStateFlow()  // read-only externally
    fun increment() { _count.value++ }
    fun decrement() { _count.value-- }
}

Coletando StateFlow

Cole StateFlow como qualquer outro fluxo. O valor mais recente é emitido imediatamente durante a coleta.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val state = MutableStateFlow("loading")
    launch {
        state.collect { println("State: $it") }
    }
    delay(50); state.value = "success"
    delay(50); state.value = "idle"
    delay(50)
    coroutineContext.cancelChildren()
}

StateFlow é Conflacionado

StateFlow só emite quando o valor muda. Se você definir o mesmo valor duas vezes, ocorrerá apenas uma emissão — valores consecutivos duplicados são mesclados.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val flow = MutableStateFlow("A")
    launch {
        flow.collect { println("Received: $it") }
    }
    delay(50)
    flow.value = "A"  // no emission — same value
    flow.value = "B"  // emits
    flow.value = "B"  // no emission — same value
    flow.value = "C"  // emits
    delay(50)
    coroutineContext.cancelChildren()
}

StateFlow no ViewModel

O padrão canônico de ViewModel: MutableStateFlow privado, alterado pela lógica de negócio, e StateFlow público, observado pela interface do usuário.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
sealed class UiState { object Loading : UiState(); data class Success(val data: String) : UiState(); data class Error(val msg: String) : UiState() }
class MyViewModel(scope: CoroutineScope) {
    private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
    val uiState: StateFlow<UiState> = _uiState.asStateFlow()
    init {
        scope.launch {
            delay(100)  // simulate load
            _uiState.value = UiState.Success("Hello!")
        }
    }
}

Atualização Atômica

Use update { } para atualizar atomicamente o estado com base no valor atual — isso é importante para atualizações concorrentes.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val counter = MutableStateFlow(0)
    List(100) {
        launch(Dispatchers.Default) {
            counter.update { it + 1 }  // thread-safe atomic update
        }
    }.forEach { it.join() }
    println("Counter: ${counter.value}")  // 100
}

compareAndSet para Atualizações Otimistas

compareAndSet(expect, update) só define o novo valor se o valor atual corresponder a expect. É útil para concorrência otimista.

import kotlinx.coroutines.flow.*
fun main() {
    val state = MutableStateFlow("idle")
    val changed = state.compareAndSet("idle", "loading")
    println("Changed: $changed, Value: ${state.value}")  // true, loading
    val changed2 = state.compareAndSet("idle", "error")  // won't change
    println("Changed: $changed2, Value: ${state.value}") // false, loading
}

StateFlow versus LiveData

StateFlow funciona sem o ciclo de vida do Android. LiveData considera o ciclo de vida, mas funciona somente no Android. Prefira StateFlow para ViewModels compartilhados com KMP.

import kotlinx.coroutines.flow.*
// StateFlow: pure Kotlin, works in commonMain
// val state = MutableStateFlow("value")

// LiveData: Android-only, lifecycle-aware
// val liveData = MutableLiveData("value")

// In Compose, collect StateFlow with:
// val state by viewModel.uiState.collectAsState()
fun main() { println("StateFlow: multiplatform; LiveData: Android-only") }

stateIn: Convertendo um Fluxo Frio em StateFlow

flow.stateIn(scope, started, initialValue) converte um fluxo frio em um StateFlow quente, compartilhando uma assinatura entre todos os coletores.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val cold = flow {
        println("Fetching...")
        delay(100)
        emit("data")
    }
    val hot: StateFlow<String> = cold.stateIn(
        scope = this,
        started = SharingStarted.Lazily,
        initialValue = "loading"
    )
    launch { hot.collect { println("A: $it") } }
    launch { hot.collect { println("B: $it") } }
    delay(200)
    coroutineContext.cancelChildren()
}

Estratégias de SharingStarted

Imediatamente: inicia na hora. De forma preguiçosa: inicia com o primeiro coletor. WhileSubscribed(stopTimeout): para quando não há coletores e reinicia quando um deles se inscreve.

import kotlinx.coroutines.flow.*
// Eagerly: upstream starts right away
// SharingStarted.Eagerly

// Lazily: waits for first subscriber
// SharingStarted.Lazily

// WhileSubscribed: stops 5s after last subscriber
// SharingStarted.WhileSubscribed(5000)

// Typical ViewModel usage:
// val uiState = repo.dataFlow.stateIn(viewModelScope, WhileSubscribed(5000), Loading)

Observando Estado Derivado

Derive um novo StateFlow de um existente usando map + stateIn. O fluxo derivado é atualizado sempre que a fonte muda.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val count = MutableStateFlow(5)
    val doubled = count.map { it * 2 }.stateIn(this, SharingStarted.Eagerly, 10)
    println(doubled.value)  // 10
    count.value = 7
    delay(50)
    println(doubled.value)  // 14
    coroutineContext.cancelChildren()
}

Verificação Rápida

O que StateFlow faz quando você define o mesmo valor duas vezes?

Recapitulação

StateFlow é um fluxo quente, sempre com valor e conflacionado. Use MutableStateFlow internamente e exponha StateFlow externamente. Use atualização para alterações concorrentes e stateIn() para converter fluxos frios.

Perguntas Frequentes

A aula “StateFlow: contêiner de estado ativo para a interface” é grátis?

Sim — o texto completo de “StateFlow: contêiner de estado ativo para a interface” é 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 “StateFlow: contêiner de estado ativo para a interface”?

Use StateFlow como contêiner reativo de estado e observe-o em ViewModels. 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 1 de 4.

Quanto tempo leva a aula “StateFlow: contêiner de estado ativo para a interface”?

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

  1. StateFlow: contêiner de estado ativo para a interface
  2. SharedFlow: barramentos de eventos e eventos de disparo único
  3. Convertendo Flow frio em ativo com shareIn e stateIn
  4. Testando StateFlow e SharedFlow com Turbine
← Voltar para Kotlin Academy