100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace

Kotlin Flow Cheat Sheet

Kotlin Flow Cheat Sheet

Building, transforming, and collecting cold asynchronous streams with Kotlin Flow, plus StateFlow/SharedFlow for hot state.

2 PagesIntermediateMar 4, 2026

Building & Collecting a Flow

Flow is cold: the block only runs when collected, and runs fresh per collector.

kotlin
import kotlinx.coroutines.flow.*import kotlinx.coroutines.*fun numbers(): Flow<Int> = flow {    for (i in 1..5) {        delay(100)          // suspend inside the builder is fine        emit(i)               // push a value downstream    }}suspend fun main() {    numbers().collect { value ->        println(value)          // 1, 2, 3, 4, 5 -- printed as they're emitted    }}// flowOf and asFlow for simple sourcesflowOf(1, 2, 3)listOf(1, 2, 3).asFlow()

Transforming Operators

Flow supports familiar sequence-like operators, all suspend-aware.

kotlin
numbers()    .map { it * it }    .filter { it % 2 == 0 }    .take(3)    .onEach { println("saw $it") }    .catch { e -> println("caught: $e") }     // catches upstream exceptions    .collect { println("result: $it") }// flatMapConcat / flatMapMerge / flatMapLatest for flows-of-flowssearchQuery    .debounce(300)    .flatMapLatest { query -> searchApi(query) }   // cancels previous search on new input    .collect { results -> render(results) }

Context Preservation & flowOn

Flow preserves the collector's context; flowOn changes upstream dispatch.

kotlin
fun heavyWork(): Flow<Int> = flow {    for (i in 1..5) {        Thread.sleep(50)      // pretend CPU-bound work        emit(i)    }}.flowOn(Dispatchers.Default)   // upstream (the flow{} builder) runs on Defaultsuspend fun run() {    withContext(Dispatchers.Main) {        heavyWork().collect { value ->            updateUI(value)      // collect lambda runs on Main, as expected        }    }}

StateFlow & SharedFlow

Hot flows for UI state (StateFlow) and event broadcasting (SharedFlow).

kotlin
class CounterViewModel : ViewModel() {    private val _count = MutableStateFlow(0)      // requires an initial value    val count: StateFlow<Int> = _count.asStateFlow()    fun increment() {        _count.update { it + 1 }        // atomic update    }}class EventBus {    private val _events = MutableSharedFlow<String>(replay = 0, extraBufferCapacity = 1)    val events: SharedFlow<String> = _events.asSharedFlow()    suspend fun publish(event: String) = _events.emit(event)}// Collecting StateFlow in Composeval count by viewModel.count.collectAsStateWithLifecycle()

StateFlow vs SharedFlow vs Flow

Choosing the right stream type.

  • Flow- cold, no state, runs fresh per collector, for one-shot async sequences
  • StateFlow- hot, always has a current value, conflates rapid updates, ideal for UI state
  • SharedFlow- hot, configurable replay/buffer, ideal for one-off events (snackbars, navigation)
  • channelFlow- builder for flows that need concurrent emit() from multiple coroutines
  • stateIn / shareIn- convert a cold Flow into a hot StateFlow/SharedFlow scoped to a CoroutineScope
Pro Tip

Don't put one-off events (like 'show a toast') in a StateFlow — because it always replays its latest value to new collectors, a screen rotation or re-subscription will re-fire the last event; use SharedFlow with replay=0 for events, and reserve StateFlow strictly for durable state.

Was this cheat sheet helpful?

Explore Topics

#KotlinFlow#KotlinFlowCheatSheet#Programming#Intermediate#BuildingCollectingAFlow#TransformingOperators#ContextPreservationFlowOn#StateFlowSharedFlow#Concurrency#CheatSheet#SkillVeris
Advertisement
Sri Hayavadhana Info-Tech

Professional Web Designing Services

  • Responsive Websites
  • E-commerce Solutions
  • SEO Friendly Design
  • Fast & Secure
  • Support & Maintenance
Get a Free Quote

Share this Cheat Sheet