In Kotlin Coroutines, Flow can be categorized into Cold Flows and Hot Flows based on how they emit values and manage their state.
Cold Flow
- Definition: A Cold Flow is lazy and starts emitting values only when an active collector exists.
- Behavior: Every time a new collector subscribes, the flow restarts and produces fresh data.
- Examples:
flow {},flowOf(),asFlow(),channelFlow {}.
Example of Cold Flow in Jetpack Compose
@Composable
fun ColdFlowExample() {
val flow = flow {
for (i in 1..5) {
delay(1000)
emit(i)
}
}
val scope = rememberCoroutineScope()
var text by remember { mutableStateOf("Waiting...") }
LaunchedEffect(Unit) {
flow.collect { value ->
text = "Cold Flow Emitted: $value"
}
}
Text(text = text, fontSize = 20.sp, modifier = Modifier.padding(16.dp))
}
Explanation
- The
flowemits values every second. - When
LaunchedEffectstarts, the collector receives values. - Each new collector gets fresh emissions from the beginning.
Hot Flow
- Definition: A Hot Flow emits values continuously, even without collectors.
- Behavior: The emission does not restart for every collector.
- Examples:
StateFlow,SharedFlow,MutableStateFlow,MutableSharedFlow.
Example of Hot Flow using StateFlow in Jetpack Compose
class HotFlowViewModel : ViewModel() {
private val _stateFlow = MutableStateFlow(0) // Initial state
val stateFlow: StateFlow<Int> = _stateFlow.asStateFlow()
init {
viewModelScope.launch {
while (true) {
delay(1000)
_stateFlow.value += 1
}
}
}
}
@Composable
fun HotFlowExample(viewModel: HotFlowViewModel = viewModel()) {
val count by viewModel.stateFlow.collectAsState()
Text(text = "Hot Flow Counter: $count", fontSize = 20.sp, modifier = Modifier.padding(16.dp))
}
Explanation
MutableStateFlowholds a state that is updated every second.- Even if no collectors exist,
stateFlowkeeps its last emitted value. - When
collectAsState()is called, it emits the latest value instead of restarting.
Key Differences
| Feature | Cold Flow | Hot Flow |
|---|---|---|
| Starts Emitting | When collected | Immediately (even without collectors) |
| Replays Values | No (new collector starts fresh) | Yes (new collector gets the latest value) |
| Examples | flow {}, flowOf(), asFlow() |
StateFlow, SharedFlow |
| Use Case | Fetching fresh data from API | UI State management |
Cold vs Hot Flow with SharedFlow
If you want hot flow behavior but also want to replay some past emissions, use SharedFlow.
Example using SharedFlow
class SharedFlowViewModel : ViewModel() {
private val _sharedFlow = MutableSharedFlow<Int>(replay = 2) // Replays last 2 values
val sharedFlow: SharedFlow<Int> = _sharedFlow.asSharedFlow()
init {
viewModelScope.launch {
var count = 0
while (true) {
delay(1000)
_sharedFlow.emit(count++)
}
}
}
}
@Composable
fun SharedFlowExample(viewModel: SharedFlowViewModel = viewModel()) {
val scope = rememberCoroutineScope()
var text by remember { mutableStateOf("Waiting...") }
LaunchedEffect(Unit) {
scope.launch {
viewModel.sharedFlow.collect { value ->
text = "Shared Flow Emitted: $value"
}
}
}
Text(text = text, fontSize = 20.sp, modifier = Modifier.padding(16.dp))
}
Explanation
MutableSharedFlowis a hot flow that emits values every second.- It replays the last 2 values for new collectors.
- Unlike
StateFlow, it does not hold a default value.
When to Use What?
| Use Case | Recommended Flow |
|---|---|
| Fetching fresh API data | Cold Flow |
| UI state that persists across collectors | StateFlow |
| Broadcasting events to multiple collectors | SharedFlow |
Conclusion
- Cold Flow is useful when you need fresh emissions per collection (like API calls).
- Hot Flow (
StateFlow,SharedFlow) is useful for UI state management and broadcasting updates. - Use
StateFlowfor single state holder andSharedFlowfor event-based broadcasting.







