Kotlin Tutorial · Advanced Kotlin · Lesson 27 of 31
Kotlin Flow
Handle streams of values asynchronously with Flow: building, transforming, collecting and StateFlow.
Cold flows
A Flow emits a sequence of values over time. It's cold: nothing runs until you collect. Operators such as
map, filter, take and onEach work like collection operations but are suspending.
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.runBlocking
fun prices(): Flow<Double> = flow {
println("flow started")
for (p in listOf(10.0, 10.5, 9.8, 11.2)) {
delay(10)
emit(p)
}
}
fun main() = runBlocking {
val flow = prices().map { it * 1.2 }.filter { it > 12 }
println("nothing has run yet")
flow.collect { println("price with tax: ${"%.2f".format(it)}") }
println("max: ${prices().reduce { a, b -> maxOf(a, b) }}")
}
Output
nothing has run yet flow started price with tax: 12.60 price with tax: 13.44 flow started max: 11.2
Run this on your computer — see “Get Started” for setup.
StateFlow
StateFlow is a hot flow that always holds a current value: the standard way to expose UI state from an
Android ViewModel. Collectors get the latest value and every update.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
class CartViewModel {
private val _count = MutableStateFlow(0)
val count: StateFlow<Int> = _count.asStateFlow()
fun add() = _count.update { it + 1 }
}
fun main() = runBlocking {
val vm = CartViewModel()
val ui = launch {
vm.count.take(3).collect { println("render badge: $it") }
}
delay(50)
vm.add()
delay(50)
vm.add()
ui.join()
println("final: ${vm.count.value}")
}
Output
render badge: 0 render badge: 1 render badge: 2 final: 2
Run this on your computer — see “Get Started” for setup.
Test yourself
What does it mean that a Flow is cold?
It caches valuesIts code runs only when something collects itIt runs on a background threadIt can't be cancelled
Show answer
Answer: Its code runs only when something collects it