Kotlin

Kotlin Flows Examples

The Kotlin programming language introduces the potent asynchronous programming notion which is known as Kotlin flows. It offers a reactive and declarative method for dealing with asynchronous data sequences or streams. Compared to conventional callback-based systems, flows are intended to handle the asynchronous processes such as network requests or database queries more effectively and briefly.

A flow is fundamentally a series of values that are released with time. Multiple downstream components may asynchronously consume these data. The native sequences in Kotlin (such as lists and arrays) are comparable to flows but with additional functionality to manage the asynchronous activities. Coroutines are little threads that may be utilized to carry out the asynchronous tasks in a planned and orderly fashion. In this guide, we will discuss all the uses of Kotlin flows via the code examples using the Coroutine packages.

Syntax:

To start using the Kotlin flows, you need to import the necessary classes and functions from the Kotlin standard library, i.e. Flow class, collect, flow, and map function, from the kotlinx.coroutines.flow package of Kotlin. Here are the fundamental aspects of Kotlin flows’ syntax:

import kotlinx.coroutines.flow.Flow

import kotlinx.coroutines.flow.collect

import kotlinx.coroutines.flow.flow

The “flow” builder function can be employed to create a flow. It lets you outline an arrangement of values that are emitted by the flow. In this following example syntax, we define a flow that emits three integers – 4, 5, and 7 – via the user-defined “Create” function:

fun Create(): Flow<Int> = flow {

emit(4)

emit(5)

emit(7)

}

To consume the values that are emitted by a flow, you can use the “collect” function from the kotlinx.coroutines.flow package. It should be used within the main() function of the program. It allows you to iterate over the emitted values and perform actions on them:

fun main() {

val f = Create()

f.collect { value ->

println(value)

}

}

You can also apply the operators to transform, filter, or combine multiple flows. For example, the map operator allows you to transform the emitted values:

fun Double(): Flow<Int> = flow {

emit(4)

emit(5)

emit(7)

}.map { value ->

value * 3

}

To consume this transformed flow, you can use the “collect” function as we did previously within the main() function of the program code:

fun main() {

val db = Double()

db.collect { value ->

println(value)

}

}

Example 1:

Let’s begin with the first illustration of this guide to demonstrate and discuss the use of Kotlin “flows” in the Kotlin language with the help of some useful flow packages and flow functions. Using the “flow builder” function, applying the operators, and using the “collect” function, you can create and consume flows to handle the asynchronous data streams in a reactive and declarative manner.

The code starts with the imports of necessary classes and functions from the kotlinx.coroutines.flow package and the kotlinx.coroutines.runBlocking function from the kotlinx.coroutines package. The “create” function is defined via the “fun” keyword which yields a flow of integers (Flow<Int>). Within the flow builder, a sequence of values is released using the emit function, i.e. 5, 2, and 9. Each call to emit adds value to the flow.

Here starts the main() method of Kotlin code. In the “main” function, we call the “runBlocking” to create a coroutine scope that can execute the suspending functions. This enables us to employ the “collect” function which is referred to as a hanging function. The suspended functions and coroutines are combined to build flows. A function that may be suspended and then resumed without stopping the thread is known as a suspending function.

The “create” function is invoked and its returned flow is assigned to the “f” variable. The emitted values 5, 2, and 9 are used as assigned values. We cast off the “collect” method on the “f” flow. It accepts a lambda function as a parameter, and the lambda function is called for each value that the flow emits. The lambda function in this situation only accepts the single “v” input which stands for the output value. Inside the lambda function, the println(v) function prints each emitted value of “v”.

import kotlinx.coroutines.flow.Flow

import kotlinx.coroutines.flow.collect

import kotlinx.coroutines.flow.flow

import kotlinx.coroutines.runBlocking

fun Create(): Flow<Int> = flow {

emit(5)

emit(2)

emit(9)

}

fun main() = runBlocking {

val f = Create()

f.collect { v ->

println(v)

}

}

When the program is executed, the output console prints the emitted values (5, 2, and 9) sequentially as they are collected from the flow. This is how a simple flow can be created in the Kotlin programming using the flow builder and the consumption of its values using the “collect” function.

Example 2:

Let’s move toward the second example of this guide using the code that is mentioned in the following. The essential classes and methods are imported into the code first from the kotlinx.coroutines.flow package to start working with Kotlin flows like flow, collect, map, runBlocking, etc.

The function named “DoubleFlow” is defined using the “fun” keyword which returns a flow of integers (Flow<Int>). This function denotes a flow that releases three values: 4, 2, and 7. The “flow” builder is cast-off to generate the flow in this program. Inside the flow builder, the “emit” method is utilized to release the individual values in the sequence.

In this case, the values 4, 2, and 7 are emitted in that order. After defining the emission of values, the map operator is applied to the flow. The v * 2 expression is used by the map operator to change each emitted value by doubling it. So, the emitted values are transformed to 8, 4, and 14. Here comes the execution of the “main” function which holds a runBlocking block (used to execute the suspended code), the DoubleFlow method is invoked, and the yielded flow is allocated to the “df” variable. The “collect” function is then called on the “df” flow. This method is utilized to assemble and consume the emanated values from the current flow. When the lambda function is passed to the “collect” method, each emitted value (v) is printed using the println() function.

import kotlinx.coroutines.flow.Flow

import kotlinx.coroutines.flow.collect

import kotlinx.coroutines.flow.flow

import kotlinx.coroutines.flow.map

import kotlinx.coroutines.runBlocking

fun DoubleFlow(): Flow<Int> = flow {

emit(4)

emit(2)

emit(7)

}.map { v ->

v * 2

}

fun main() = runBlocking {

val df = DoubleFlow()

df.collect { v ->

println(v)

}

}

When the code is executed, it produces the output that is revealed in the following image. This output corresponds to the transformed values that are emitted by the flow after applying the map operator, i.e. 8, 4, and 14, at three separate lines (double of original values).

Conclusion

This article demonstrates that Kotlin flows, as a whole, offer a strong and simple method to handle the asynchronous data streams reactively and expressively. They provide a more effective and scalable asynchronous programming in Kotlin. The code illustrations that are previously shown discussed how to create and use the Kotlin Flows. The first example demonstrates how to establish a simple flow and gather the data it emits, while the second example demonstrates how to use the map operator to alter the values that the flow emits.

About the author

Saeed Raza

Hello geeks! I am here to guide you about your tech-related issues. My expertise revolves around Linux, Databases & Programming. Additionally, I am practicing law in Pakistan. Cheers to all of you.