Operators are at the heart of Kotlin Flow, like every reactive Framework. It allows manipulating items as they go from observable to observer.
Here are the 9 very important but less known Kotlin Flow operators with graphics and examples.
We are what we repeatedly do. Excellence, then, is not an act, but a habit. Try out Justly and start building your habits today!
Reduce operator allows performing operation over all items of the flow to reduce them into one item.
For example, the below reduce function performs sum of all items and thus we get result 6
.
flowOf(1, 2, 3)
.reduce { acc, value -> acc + value }
Output:
6
Similar to reduce
but allows result of any type.
For example, here we are starting with a string and performing string concatenation of all items.
flowOf(1, 2, 3)
.fold("hello", { acc, value -> acc + value })
Output:
hello123
Debounce operator emits an item from a Flow only if a particular timespan has passed without it emitting another item
For example, consider you are designing a search box and you have a flow of user input.
In that case, you will want search query to fire only when user does not type for 500ms, otherwise you will end up querying only so many times. So as long as user types another character before 500ms passes, debounce will not send that item. However, the last item will always be sent when user does not type anything for 500ms.
flow {
emit(1)
delay(90)
emit(2)
delay(90)
emit(3)
delay(1010)
emit(4)
delay(1010)
emit(5)
}.debounce(1000)
Output:
3, 4, 5
Similar to debounce
, it’s also used to filter items from the Flow
but it has one important difference — Instead of checking interval from the last item, sample
operator will run periodically and will send 1 latest item per interval.
For example, here we have a flow that keeps emitting an item every 50ms and if we apply sample
of 100ms, we will get every other item.
flow {
repeat(10) {
emit(it)
delay(50)
}
}.sample(100)
Output:
1,3,5,7,9
Remember, if we had used debounce
here, we will only get item 9
.
flatmapMerge
operator maps every item of the Flow with a new Flow provided by transform operation and then merges the items of those flows and flattens it.
Consider the following example
flowOf(1, 2, 3)
.flatMapMerge { flowOf("$it a", "$it b") }
Output:
2a, 2b, 1a, 1b, 3a, 3b
Here Flow
of items 1
, 2
and 3
is mapped with a new Flow
, that emits 2 items per 1 item of the previous Flow
.
Those flows are then merge together and are flattened, so when you collect at the end, you will get flat items from all Flows.
Similar to flatmapMerge
but here flows are concatenated instead of merge.
Remember flatmapMerge
has better performance as it can process Flows in parallel.
The example above is self explanatory.
This is a bit hard to understand as this does not really change flow of the items but rather helps with performance.
Consider this example
flowOf("A", "B", "C")
.onEach { delay(300) }
.collect { println("$it") }
// Output takes 900ms as all items are processed sequentially
Here we have flow of 3 items and they are emitted immediately.
However, as we have an operator onEach
with 300ms delay, collect will process all items sequentially and that means it will take total 900ms for collection.
If we add a buffer between onEach
operator and collect
, it will create a separate coroutine to collect items from onEach
operator in parallel as per the provided capacity of buffer
. That will allow us to collect all items in 300ms as all operator operations don’t need to happen sequentially.
flowOf("A", "B", "C")
.onEach { delay(300) }
.buffer(3)
.collect { println("$it") }
// Output takes 300ms as all items are processed in parallel at buffer operator and delivered to collect immediately.
This operator merges two flows with the provided operation
function.
Here — Latest item of the Flows are always combined.
As shown in the snippet below, first Flow emits item 1
and 2
. Thus only latest item 2
is combined with the every item of the second Flow.
flowOf("1", "2")
.combine(flowOf("a", "b", "c"), {a, b -> a + b })
Output:
2a, 2b, 2c
Similar to combine
, this also merges two Flows but it will broadcast one item when both Flow emits 1 item each.
The resulting flow completes as soon as one of the flows completes and cancel is called on the remaining flow.
flowOf("1", "2")
.zip(flowOf("a", "b", "c"), {a, b -> a + b })
Output:
1a, 2b
As shown here, only two zipped
items are emitted from the resulting flow as first Flow
has only two items.
Operators form the core of Kotlin Flow, serving a crucial role akin to that in every reactive framework. They provide the essential functionality for manipulating items as they transition from the observable source to the observer, enabling developers to efficiently handle and transform data streams in a reactive programming model.
This makes Kotlin Flow a powerful tool for creating responsive and resilient applications.
That’s it for today, hope you learned something new!
Thanks for your support!
Get started today
Let's build the next
big thing!
Let's improve your business's digital strategy and implement robust mobile apps to achieve your business objectives. Schedule Your Free Consultation Now.
Get Free ConsultationGet started today
Let's build the next big thing!
Let's improve your business's digital strategy and implement robust mobile apps to achieve your business objectives. Schedule Your Free Consultation Now.
Get Free Consultation