SyntaxStudy
Sign Up
Kotlin Flows for Asynchronous Streams
Kotlin Beginner 1 min read

Flows for Asynchronous Streams

Kotlin Flow is the coroutines-based answer to reactive streams. A Flow represents an asynchronous stream of values that are emitted over time. Unlike a sequence, a flow is cold: the producer code does not run until a terminal operator such as collect is called. The flow builder uses the emit function to produce values. Intermediate operators (map, filter, transform, take, debounce, etc.) are lazy and return new Flow objects. Terminal operators such as collect, toList, first, and reduce trigger execution. StateFlow and SharedFlow are hot flows used in Android and other UI frameworks to represent state and events. StateFlow always has a current value and replays it to new collectors, making it a direct replacement for LiveData.
Example
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

fun numberFlow(): Flow<Int> = flow {
    println("Flow started")
    for (i in 1..5) {
        delay(100)
        emit(i)
    }
}

fun main() = runBlocking {
    // Basic collection
    numberFlow()
        .map     { it * it }
        .filter  { it > 5 }
        .collect { println("Received: $it") }

    println()

    // flowOf and asFlow
    flowOf("a", "b", "c").collect { print("$it ") }
    println()
    (1..3).asFlow().collect { print("$it ") }
    println()

    // transform — emit multiple values per upstream item
    (1..3).asFlow()
        .transform { n ->
            emit("before $n")
            emit(n * 10)
        }
        .collect { println(it) }

    // StateFlow
    val stateFlow = MutableStateFlow(0)
    val job = launch {
        stateFlow.collect { println("State: $it") }
    }
    stateFlow.value = 1
    stateFlow.value = 2
    delay(100)
    job.cancel()

    // zip two flows
    val flow1 = flowOf("One", "Two", "Three")
    val flow2 = flowOf(1, 2, 3)
    flow1.zip(flow2) { s, n -> "$s=$n" }.collect { println(it) }
}