StateFlow helps your app react to changes in data automatically. It keeps your app's state updated and UI in sync without extra work.
StateFlow for reactive state in Android Kotlin
private val _state = MutableStateFlow(initialValue) val state: StateFlow<Type> = _state // To update state: _state.value = newValue
Use MutableStateFlow to change the state inside your class.
Expose StateFlow to other classes to observe changes without allowing them to modify the state.
private val _count = MutableStateFlow(0) val count: StateFlow<Int> = _count // Update count _count.value = 5
private val _text = MutableStateFlow("") val text: StateFlow<String> = _text // Update text _text.value = "Hello"
This program creates a simple counter using StateFlow. It prints the count every time it changes. When increment() is called, the count updates and the new value prints automatically.
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.runBlocking import kotlinx.coroutines.launch class Counter { private val _count = MutableStateFlow(0) val count: StateFlow<Int> = _count fun increment() { _count.value += 1 } } fun main() = runBlocking { val counter = Counter() val job = launch { counter.count.collect { value -> println("Count is: $value") } } counter.increment() // Count becomes 1 counter.increment() // Count becomes 2 job.cancel() }
StateFlow always has a current value, so you can get it anytime with .value.
Use collect to listen for changes and update UI or other parts of your app.
Remember to cancel collectors when they are no longer needed to avoid memory leaks.
StateFlow holds and emits state updates reactively.
Use MutableStateFlow to change state, and expose StateFlow to observe it.
Collect StateFlow to react to changes and update your UI automatically.
Practice
StateFlow in Android Kotlin development?Solution
Step 1: Understand StateFlow's role
StateFlow is designed to hold a state value and emit updates whenever the state changes.Step 2: Compare with other options
Options A, B, and D describe unrelated tasks like storage, networking, or database management, which are not StateFlow's purpose.Final Answer:
To hold and emit state updates reactively to observers -> Option AQuick Check:
StateFlow = reactive state holder [OK]
- Confusing StateFlow with networking or storage APIs
- Thinking StateFlow stores data permanently
- Assuming StateFlow manages database directly
Solution
Step 1: Recall MutableStateFlow syntax
The correct way to create a mutable StateFlow is usingMutableStateFlow(initialValue).Step 2: Check each option
val state = StateFlow<Int>(0) uses StateFlow constructor which is not allowed. val state = mutableStateFlowOf(0) uses a non-existent function. val state = StateFlow.mutable(0) uses invalid syntax.Final Answer:
val state = MutableStateFlow(0) -> Option BQuick Check:
MutableStateFlow = mutable state holder [OK]
- Trying to instantiate StateFlow directly
- Using wrong function names like mutableStateFlowOf
- Incorrect syntax for mutable StateFlow creation
val state = MutableStateFlow(0) state.value = 5 println(state.value)
Solution
Step 1: Understand MutableStateFlow value assignment
MutableStateFlow'svalueproperty can be updated directly, changing the current state.Step 2: Trace the code execution
Initially, state.value is 0. Then it is set to 5. Printing state.value outputs 5.Final Answer:
5 -> Option DQuick Check:
state.value after assignment = 5 [OK]
- Assuming initial value remains unchanged
- Thinking value is nullable and prints null
- Expecting compilation error due to direct assignment
val state = MutableStateFlow(0)
fun updateState(newValue: Int) {
state.emit(newValue)
}Solution
Step 1: Check usage of emit on MutableStateFlow
Theemitfunction is a suspend function and requires a coroutine context to be called.Step 2: Analyze the code context
The functionupdateStateis not marked suspend and does not launch a coroutine, so callingemithere causes an error.Final Answer:
emit is a suspend function and must be called from a coroutine -> Option CQuick Check:
emit requires coroutine context [OK]
- Calling emit outside coroutine without suspend
- Confusing emit with direct value assignment
- Assuming MutableStateFlow has no initial value
Solution
Step 1: Understand encapsulation of state
To prevent external modification, keep MutableStateFlow private inside ViewModel.Step 2: Expose read-only StateFlow
UseasStateFlow()to expose a read-only StateFlow to observers outside the ViewModel.Step 3: Evaluate other options
Declare a public MutableStateFlow and update it directly from outside the ViewModel breaks encapsulation. Expose the MutableStateFlow as a public property and update it internally exposes mutable state publicly. Use a regular Flow instead of StateFlow for state updates changes the reactive type unnecessarily.Final Answer:
Keep a private MutableStateFlow and expose a public StateFlow using asStateFlow() -> Option AQuick Check:
Private MutableStateFlow + public asStateFlow() = best practice [OK]
- Making MutableStateFlow public and mutable externally
- Not using asStateFlow() to expose read-only state
- Replacing StateFlow with Flow unnecessarily
Ready to prove it?
Pass the test and this pattern moves unknown
