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.
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.
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) } }
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 ...