StateFlow is a special type of Flow designed to hold a single, up-to-date state value.
It is similar to a LiveData but built specifically for Kotlin coroutines.
StateFlow is hot, always active, and always contains a current state.
// Creating a StateFlow
private val _count = MutableStateFlow(0)
val count = _count.asStateFlow()
// Updating value
fun increment() {
_count.value++
}
// Collecting StateFlow
launch {
count.collect { value ->
println("Received: $value")
}
}
Every collector immediately receives the current value, even if it started late.
Although both belong to the Flow family, they are designed for different purposes.
| Feature | StateFlow | SharedFlow |
|---|---|---|
| Initial value | Required | Not required |
| Replays last value | Always 1 | Configurable (0, 1, many) |
| Use case | Holding and observing state | Broadcasting events |
| Supports multiple collectors | Yes | Yes |
| Missed values when collector joins late | No (gets latest instantly) | Yes, unless replay > 0 |
| Hot or cold? | Hot | Hot |
| Memory usage | Holds 1 value | Holds replayed values + buffer |
Both are used to observe data changes, especially in Android UI. But they have important differences.
| Feature | StateFlow | LiveData |
|---|---|---|
| Lifecycle awareness | No | Yes |
| Thread safety | Always thread-safe | Partially safe |
| Requires coroutine? | Yes | No |
| Initial value | Required | Optional |
| Designed for | Kotlin coroutines | Android UI |
| Backpressure handling | Excellent (Flow-based) | Basic |
| Transformation operators | Rich (map, flatMap, combine) | Limited |
| Cold or hot? | Hot | Hot |
Google recommends using StateFlow for new coroutine-based ViewModels, and using LiveData only when lifecycle awareness is required and you're not using flows heavily.
private val _username = MutableLiveData("")
val username: LiveData = _username
private val _username = MutableStateFlow("")
val username = _username.asStateFlow()
The StateFlow version is more efficient, coroutine-friendly, and easier to test.