0
0
KotlinHow-ToBeginner · 4 min read

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 MutableStateFlow directly instead of a read-only StateFlow, 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 .value to 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.