1 – Introduction
As the complexity of applications grows, handling multiple asynchronous events in real time becomes essential. To this end, Kotlin offers a powerful tool called Flow
, which simplifies the management of asynchronous data flows.
In this article, we will explore:
- What is a
Flow
and how does it differ from other approaches likesuspend
andasync
. - Real use cases of
Flow
. - Tools like Turbine to test data flows.
2 – What is a Flow
?
Kotlin Flow is a tool for handling asynchronous data flows. It works like a pipeline that emits values over time, allowing you to handle data streams efficiently.
Main Features:
-
Asynchronous:
Flow
emits values in a non-blocking manner. -
Cold Stream : A
Flow
only starts emitting values when there is a "sink" (i.e. when someone consumes the data). - Cancellable: If the collector is canceled, the flow is also automatically canceled.
3 – Creating a Flow
Simple Example of a Flow
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val flow = flow {
for (i in 1..3) {
emit(i) // Emits a value
delay(1000) // Simulates a delay between emissions
}
}
flow.collect { value ->
println("Received: $value")
}
}
Console Output
Received: 1
Received: 2
Received: 3
Explanation:
-
emit
: Sends values to the stream. -
collect
: Consumes the values emitted by the stream.
4 – Comparison: Flow vs. Other Approaches
Appearance | Flow | suspend | async |
---|---|---|---|
Continuous data flow | Yes | No | No |
Multiple values | Yes | No (only one value per call) | No (returns a single value). |
Cancellable | Yes | Yes | Yes |
Typical example | Event streams | Simple asynchronous calls | Parallel computations. |
5 – Transforming Data with Flow
The real power of Flow
lies in its ability to transform the data output with operators.
Example: Using operators like map
and filter
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val flow = flow {
for (i in 1..5) {
emit(i)
}
}
flow
.filter { it % 2 == 0 } // Filter even values
.map { it * 10 } // Multiplies the values by 10
.collect { value ->
println("Transformed: $value")
}
}
Console Output
Transformed: 20
Transformed: 40
6 – Testing Flows with Turbine
Turbine is a library that facilitates the validation of values emitted by a Flow
.
Example with Turbine
import app.cash.turbine.test
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun main() = runTest {
// Creates a stream that emits two values with a delay between them
val flow = flow {
println("Emitting value 1")
emit(1) // Emit the first value
delay(500) // Wait 500ms
println("Emitting value 2")
emit(2) // Emit the second value
}
// Test the flow
flow.test {
val firstValue = awaitItem() // Wait for the first value
println("Value received from stream: $ firstValue ")
assert(firstValue == 1) // Validates the first value
val secondValue = awaitItem() // Wait for the second value
println("Value received from stream: $ secondValue ")
assert(secondValue == 2) // Validates the second value
awaitComplete() // Check if the stream has completed
println("Flow completed successfully!")
}
}
Expected departure at terminal
Emitting value 1
Value received from stream: 1
Emitting value 2
Value received from stream: 2
Flow completed successfully!
7 – Real Use Cases of Flow
7.1 – Real Time Update
In a chat application, you can use a Flow
to stream new messages to the user interface as they arrive from the server.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val messages = flow {
val newMessages = listOf("Hi", "How are you?", "See you soon!")
for (message in newMessages) {
emit(message)
delay(1000) // Simulates interval between messages
}
}
messages.collect { message ->
println("New message: $message")
}
}
7.2 – Batch Data Processing
Imagine a system that needs to process large batches of data at regular intervals. Flow
makes this implementation easy.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val batchFlow = flow {
val lots = listOf("Lot1", "Lot2", "Lot3")
for (lot in lots) {
issue(batch)
delay(2000) // Simulates processing time
}
}
batchFlow.collect { lot ->
println("Processing: $batch")
}
}
8 – Conclusion
Flow
is a powerful tool for handling asynchronous data in Kotlin , allowing you to emit, transform, and consume values in real time. It is essential for building modern applications, especially in scenarios that require handling continuous streams of events.
Summary:
-
Flow
is ideal for continuous, cancelable data streams. - Operators like
map
andfilter
make it easier to transform the outputted data. - Tools like Turbine simplify flow testing.
References:
Official Kotlin documentation on coroutines
Turbine Documentation
Top comments (0)