Kotlin Flows - Collect and CollectLatest

Kotlin Flows - Collect and CollectLatest

Understanding Collect and CollectLatest in Kotlin Flow API

Kotlin Flow API provides a powerful set of operators for manipulating flows. In this article, we'll take a closer look at two of these operators: collect and collectLatest.

What is a Flow?

Before we dive into the operators, let's first understand what a flow is.

A flow is a sequence of values that are emitted over time. You can think of it like a river that flows and carries values along with it. Just like you can use a bucket to collect water from a river, you can use operators like collect and collectLatest to collect values from a flow.

Flows are particularly useful when dealing with asynchronous data, such as data that comes from an API call.

For more detailed information on the Flows, check out our article on Introduction to Kotlin Flows.

Collecting Values from a Flow

collect and collectLatest are terminal operators in Kotlin Flow API. A terminal operator is an operation that is performed on a flow to produce a result or a side effect. In the case of collect and collectLatest, the result is the collection of the emitted values from the flow.

The collect and collectLatest operators are used to collect the emitted values from a flow.

Collect Operator in Flow

The collect operator collects all the emitted values from a flow. It suspends until all the values are emitted and collected. Here's an example:

val myFlow = flowOf(1, 2, 3)

myFlow.collect { value ->
    println(value)
}

This code creates a flow that emits the values 1, 2, and 3. The collect operator is then used to collect these values. The code inside the lambda function (the part between {}) is executed for each value emitted by the flow. In this case, we simply print the value.

The output of this code will be:

1
2
3

You might be wondering what it means for an operator to suspend. In Kotlin, suspending means that the execution of a function is paused until some condition is met. In the case of the collect operator, it suspends until all the values are emitted by the flow and collected.

You can think of the collect operator like collecting water from a river using a bucket. Each time you dip the bucket into the river, you collect some water. In this analogy, the water represents the values emitted by the flow, and the bucket represents the collect operator.

Now let's compare this with a similar operation on an array:

val myArray = arrayOf(1, 2, 3)

myArray.forEach { value ->
    println(value)
}

This code creates an array that contains the values 1, 2, and 3. The forEach operator is then used to iterate over these values. The code inside the lambda function is executed for each value in the array. In this case, we simply print the value.

The output of this code will be the same as before:

1
2
3

As you can see, collecting values from a flow using collect is similar to iterating over values in an array using forEach. Both operations allow you to access each value one by one.

CollectLatest Operator in Flow

The collectLatest operator, on the other hand, collects only the most recently emitted value from a flow. If a new value is emitted while the previous one is being processed, the processing of the previous value is cancelled, and the new value is processed instead. Here's an example:

val myFlow = flowOf(1, 2, 3).onEach { delay(100) }

myFlow.collectLatest { value ->
    println("Processing $value")
    delay(300)
    println("Done processing $value")
}

This code creates a flow that emits the values 1, 2, and 3 with a delay of 100 milliseconds between each value. The collectLatest operator is then used to collect these values. The code inside the lambda function is executed for each value emitted by the flow. In this case, we print that we are processing the value, then we introduce a delay of 300 milliseconds to simulate some processing time, and finally we print that we are done processing the value.

The output of this code will be:

Processing 1
Processing 2
Processing 3
Done processing 3

As you can see, only the processing of value 3 is completed. The processing of values 1 and 2 is cancelled because a new value is emitted before their processing is completed.

You can think of the collectLatest operator like trying to catch butterflies with a net. Each time you try to catch a butterfly (a value), another butterfly (a new value) flies by and distracts you. You let go of the first butterfly and try to catch the new one instead.