-
Notifications
You must be signed in to change notification settings - Fork 23
Flow: Intermediate operators
These intermediate operators are also called transform operators
These operators are executed for every emission of the flow
It returns a new and transformed flow
- Using the
map-operator
we can convert the form of one type of input into another type - In the example below, We have converted from
integer
toString
It seems like you want to create a table in a GitHub README file to describe three operators for Kotlin's Flow API: map
, mapNotNull
, and mapLatest
. Below is an example table format that you can use in your README file:
Operator | Description |
---|---|
map |
Transforms each emitted item by applying a given function, producing a new flow of transformed items. |
mapNotNull |
Transforms each emitted item by applying a given function, excluding null results from the new flow. |
mapLatest |
Similar to map , but only emits the result of the latest transformation when a new item is emitted. |
You can copy and paste this table into your README file and fill in the descriptions for each operator. Additionally, you can provide examples or usage patterns for better understanding. Here's a more detailed explanation of each operator:
-
map
: Themap
operator transforms each item emitted by the flow by applying a given function. It creates a new flow that emits the transformed items. This is useful when you want to perform a one-to-one transformation on each item in the flow. -
mapNotNull
: Similar tomap
, themapNotNull
operator transforms each item emitted by the flow using a given function. However, it excludes null results from the new flow. This is useful when you want to filter out null values resulting from the transformation. -
mapLatest
: ThemapLatest
operator is similar tomap
, but it only emits the result of the latest transformation when a new item is emitted in the original flow. If a new item is emitted before the previous transformation completes, the result of the previous transformation is ignored. This is useful when you want to ensure that only the latest result is considered, discarding outdated transformations.
private val flowOfIntegers = flowOf(1, 2, 3, 4, 5)
viewModelScope.launch {
flowOfIntegers.map {
it.toString()
}.collect {
if(it is String){
// Use smart cast to check if it is string
println("Received value: -->$it")
}
}
}
Received value: -->1
Received value: -->2
Received value: -->3
Received value: -->4
Received value: -->5
- Here we pass a collection of items but emit only those that pass a predicate test
Operator | Description |
---|---|
flowOfIntegers.filter { } |
Filters items emitted by the flow based on a given predicate. Only items that satisfy the predicate are included in the new flow. |
flowOfIntegers.filterNot { } |
Filters items emitted by the flow based on a given predicate. Only items that do not satisfy the predicate are included in the new flow. |
flowOfIntegers.filterIsInstance<Int>{ } |
Filters items emitted by the flow and includes only those that are instances of the specified type (Int in this case). |
val flowOfIntegers = flowOf(1, 2, 3, 4, 5)
viewModelScope.launch {
flowOfIntegers.filter {
// We use modulus function to check if the number is divisible by 2
it%2 == 0
}.collect{
println("Received value: -->$it")
}
}
Received value: -->2
Received value: -->4
- It is called a sizing operator
Operator | Description |
---|---|
flowOfIntegers.take { } |
Limits the number of items emitted by the flow to a specified count. |
flowOfIntegers.takeIf { } |
Conditional operator; takes items from the flow if a specified condition is true, otherwise returns an empty flow. |
flowOfIntegers.takeWhile { } |
Takes items from the flow as long as a specified predicate is true; stops when the predicate becomes false. |
flowOfIntegers.takeUnless { } |
Opposite of takeIf ; takes items from the flow if a specified condition is false, otherwise returns an empty flow. |
val scope = CoroutineScope(EmptyCoroutineContext)
scope.launch {
flowOfIntegers.take(2).collect{
println("Received value: -->$it")
}
}
Received value: -->1
Received value: -->2
- Filter does not cancel the upstream flow when the conditions are not met, Actually it just forwards the filtered flow.
- Take cancel the upstream flow when a certain condition is not met.
- Here we can drop an initial specified number of emissions in the flow and allow the rest
Operator | Description |
---|---|
flowOfIntegers.drop { } |
Drops a specified number of items from the beginning of the flow. |
flowOfIntegers.dropWhile { } |
Drops items from the beginning of the flow as long as a specified predicate is true; emits the rest of the items. |
val scope = CoroutineScope(EmptyCoroutineContext)
scope.launch {
flowOfIntegers.drop(1).collect{
println("Received value: -->$it")
}
}
Received value: -->2
Received value: -->3
Received value: -->4
Received value: -->5
- We can transform the data apply some predicate conditions and emit the new value,
- We can also emit multiple emissions
- This is basically applying a collection of operators together and emitting the emission downstream
Received value: -->2
Received value: -->4
fun transformOperator() {
val scope = CoroutineScope(EmptyCoroutineContext)
scope.launch {
flowOfIntegers.transform {
if((it%2)==0){
// Elements that are divisible by 2
emit(it)
}
}.collect{
println("Received value: -->$it")
}
}
}
- Using this operator we can discard the emissions in a certain period frame.
- Some emissions will be lost from this time frame
- This is helpful to drop some duplicate emissions from the period frame.
- One example is when the mouse is moving and a lot of emissions might be sent from the position coordinates of the mouse, and we might be interested in certain coordinates in it.