...

/

Understanding Flow Builder

Understanding Flow Builder

Learn about different flow builders and creating a flow.

We'll cover the following...

The flow builder is the most basic way to create a flow. All the other options are based on it.

Press + to interact
public fun <T> flowOf(vararg elements: T): Flow<T> = flow {
for (element in elements) {
emit(element)
}
}

When we understand how this builder works, we’ll understand how the flow works. The flow builder is straightforward under the hood: it just creates an object implementing the Flow interface, which calls the block function inside the collect method.

Note: The code below is simplified. In real code, there would be an additional mechanism for releasing a continuation interceptor.

Press + to interact
fun <T> flow(
block: suspend FlowCollector<T>.() -> Unit
): Flow<T> = object : Flow<T>() {
override suspend fun collect(collector: FlowCollector<T>) {
collector.block()
}
}
interface Flow<out T> {
suspend fun collect(collector: FlowCollector<T>)
}
fun interface FlowCollector<in T> {
suspend fun emit(value: T)
}

Knowing this, let’s analyze how the following code works.

package kotlinx.coroutines.app
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.test.runTest

fun main() = runTest {
   flow { // 1
       emit("A")
       emit("B")
       emit("C")
   }.collect { value -> // 2
       println(value)
   }
}
Calling the block function on the collector interface

When we call a flow builder, we create an object. However, calling collect means calling the block function on the collector interface. The block function in this example is the lambda expression defined at 1. Its receiver is the collector, defined at 2 with a lambda expression. When we define a function interface (like FlowCollector) with a lambda expression, the body of this lambda expression will be used as the body of that function interface–only function (emit in this case). So, the body of the emit function is ...