How to Use StateFlow in Kotlin for Reactive State Management
Use
StateFlow in Kotlin to hold and observe state changes reactively by creating a MutableStateFlow for updating state and exposing it as a read-only StateFlow. Collect the flow in a coroutine to react to state updates.Syntax
StateFlow is a flow that holds a single updatable data value and emits updates to collectors. You create a mutable version with MutableStateFlow and expose it as a read-only StateFlow to observers.
MutableStateFlow(initialValue): Holds the current state and allows updates.stateFlow.value: Gets or sets the current state value.stateFlow.collect { }: Collects updates reactively in a coroutine.
kotlin
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow class MyStateHolder { private val _state = MutableStateFlow("Initial") val state: StateFlow<String> = _state fun updateState(newValue: String) { _state.value = newValue } }
Example
This example shows how to create a MutableStateFlow, update its value, and collect changes in a coroutine to print updates.
kotlin
import kotlinx.coroutines.* import kotlinx.coroutines.flow.* fun main() = runBlocking { val stateFlow = MutableStateFlow("Start") // Launch a coroutine to collect state updates val job = launch { stateFlow.collect { value -> println("State updated: $value") } } // Update the state value delay(100) stateFlow.value = "Loading" delay(100) stateFlow.value = "Success" delay(100) // Wait to see output job.cancel() // Stop collecting }
Output
State updated: Start
State updated: Loading
State updated: Success
Common Pitfalls
Common mistakes when using StateFlow include:
- Not collecting the flow in a coroutine, so updates are never observed.
- Exposing
MutableStateFlowdirectly instead of a read-onlyStateFlow, which breaks encapsulation. - Updating state outside of a coroutine context that supports concurrency, causing race conditions.
Always collect StateFlow inside a coroutine and expose only the read-only StateFlow to observers.
kotlin
import kotlinx.coroutines.* import kotlinx.coroutines.flow.* class WrongExample { // Wrong: exposing mutable state directly val state = MutableStateFlow(0) fun increment() { state.value += 1 } } class RightExample { private val _state = MutableStateFlow(0) val state: StateFlow<Int> = _state fun increment() { _state.value += 1 } }
Quick Reference
Remember these key points when using StateFlow:
- MutableStateFlow: Use to update state internally.
- StateFlow: Expose to observers as read-only.
- Collect: Always collect in a coroutine to receive updates.
- Value: Use
.valueto get or set the current state.
Key Takeaways
Use MutableStateFlow to hold and update state internally and expose StateFlow for read-only access.
Collect StateFlow in a coroutine to react to state changes.
Always update StateFlow's value within a coroutine-safe context to avoid concurrency issues.
Do not expose MutableStateFlow directly to maintain encapsulation.
StateFlow always holds the latest state and emits it immediately to new collectors.