liveBook · Manning

Flow builder

As explained in Kotlin in Action, 2E

A flow builder is a Kotlin coroutines function that creates a cold Flow from a suspending block capable of emitting values.

A flow builder is the Kotlin coroutines function flow, which creates a cold Flow from a suspending block. Call emit inside the block to offer values over time; suspending functions such as delay can run between emissions. Creating the Flow performs no work until a terminal operator, usually collect, starts it. section 16.2.1 section 16.1.1

Emit values with a delay

A function can return Flow<String> from ordinary, non-suspending Kotlin code while performing suspending work inside the builder. Collecting letters starts the block, emits A, waits 200 milliseconds, and emits B. Values become available as they are emitted rather than after the entire sequence is computed. section 16.2.1 section 16.1.1

Listing 16.3 Calling suspending functions from the flow builder
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlin.time.Duration.Companion.milliseconds
 
fun main() {
    val letters = flow {
        log("Emitting A!")
        emit("A")                 #1
        delay(200.milliseconds)
        log("Emitting B!")
        emit("B")
    }
}

Use the compact Kotlin listing to see emit and delay together inside a flow builder. section 16.2.1

Keep these execution rules in mind:

  • Treat the returned Flow as inert until collection begins; collecting the same cold flow again executes its builder again, including side effects such as network requests. section 16.2.2
  • Understand emit as an asynchronous return: it invokes the collector and suspends the builder until that collector finishes processing the value. section 16.2.1 section 16.2.4
  • Build custom intermediate operators by creating a flow, collecting the upstream flow inside it, transforming each element, and emitting downstream values. section 17.3
fun Flow<Double>.averageOfLast(n: Int): Flow<Double> =
   flow {
       val numbers = mutableListOf<Double>()
       collect {
           if (numbers.size >= n) {
               numbers.removeFirst()
           }
           numbers.add(it)
           emit(numbers.average())
       }
   }

Use the custom averageOfLast operator to trace how a flow builder remains cold while collecting upstream and emitting transformed results. section 17.3

How Kotlin in Action, 2E covers it

How deep it goes
Explains syntax, cold execution, repeated collection, and FlowCollector mechanics, then applies the pattern to custom operators.
Examples
Uses delayed letters, an incremental integer flow, an infinite counter, and a rolling-average intermediate operator.
What it assumes
Assumes Kotlin coroutine and suspending-function basics while defining Flow, FlowCollector, collect, and emit through concrete execution traces.
What you can do after
Build it from scratch by returning Flow values, emitting from suspending builders, collecting them, and composing custom cold operators.
How it connects
Connects suspending functions, emit, collect, cold flows, FlowCollector, terminal operators, and intermediate operators.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Kotlin in Action, 2E. The section links point to the parts of the book it draws on.