@@ -102,7 +102,7 @@ This code prints the numbers after waiting for a second.
102
102
### Flows
103
103
104
104
Using the ` List<Int> ` result type, means we can only return all the values at once. To represent
105
- the stream of values that are being asynchronously computed, we can use a [ ` Flow<Int> ` ] [ Flow ] type just like we would use the ` Sequence<Int> ` type for synchronously computed values:
105
+ the stream of values that are being computed asynchronously , we can use a [ ` Flow<Int> ` ] [ Flow ] type just like we would use a ` Sequence<Int> ` type for synchronously computed values:
106
106
107
107
``` kotlin
108
108
import kotlinx.coroutines.*
@@ -151,11 +151,11 @@ I'm not blocked 3
151
151
152
152
Notice the following differences in the code with the [ Flow] from the earlier examples:
153
153
154
- * A builder function for [ Flow] type is called [ flow] [ _flow ] .
155
- * Code inside the ` flow { ... } ` builder block can suspend.
156
- * The ` simple ` function is no longer marked with ` suspend ` modifier.
157
- * Values are _ emitted_ from the flow using [ emit] [ FlowCollector.emit ] function.
158
- * Values are _ collected_ from the flow using [ collect] [ collect ] function.
154
+ * A builder function of [ Flow] type is called [ flow] [ _flow ] .
155
+ * Code inside a ` flow { ... } ` builder block can suspend.
156
+ * The ` simple ` function is no longer marked with a ` suspend ` modifier.
157
+ * Values are _ emitted_ from the flow using an [ emit] [ FlowCollector.emit ] function.
158
+ * Values are _ collected_ from the flow using a [ collect] [ collect ] function.
159
159
160
160
> We can replace [ delay] with ` Thread.sleep ` in the body of ` simple ` 's ` flow { ... } ` and see that the main
161
161
> thread is blocked in this case.
@@ -215,12 +215,12 @@ Flow started
215
215
<!-- - TEST -->
216
216
217
217
This is a key reason the ` simple ` function (which returns a flow) is not marked with ` suspend ` modifier.
218
- By itself, ` simple() ` call returns quickly and does not wait for anything. The flow starts every time it is collected,
219
- that is why we see "Flow started" when we call ` collect ` again.
218
+ The ` simple() ` call itself returns quickly and does not wait for anything. The flow starts afresh every time it is
219
+ collected and that is why we see "Flow started" every time we call ` collect ` again.
220
220
221
221
## Flow cancellation basics
222
222
223
- Flow adheres to the general cooperative cancellation of coroutines. As usual, flow collection can be
223
+ Flows adhere to the general cooperative cancellation of coroutines. As usual, flow collection can be
224
224
cancelled when the flow is suspended in a cancellable suspending function (like [ delay] ).
225
225
The following example shows how the flow gets cancelled on a timeout when running in a [ withTimeoutOrNull] block
226
226
and stops executing its code:
@@ -268,13 +268,13 @@ See [Flow cancellation checks](#flow-cancellation-checks) section for more detai
268
268
269
269
## Flow builders
270
270
271
- The ` flow { ... } ` builder from the previous examples is the most basic one. There are other builders for
272
- easier declaration of flows:
271
+ The ` flow { ... } ` builder from the previous examples is the most basic one. There are other builders
272
+ that allow flows to be declared :
273
273
274
- * [ flowOf] builder that defines a flow emitting a fixed set of values.
275
- * Various collections and sequences can be converted to flows using ` .asFlow() ` extension functions .
274
+ * The [ flowOf] builder defines a flow that emits a fixed set of values.
275
+ * Various collections and sequences can be converted to flows using the ` .asFlow() ` extension function .
276
276
277
- So , the example that prints the numbers from 1 to 3 from a flow can be written as:
277
+ For example , the snippet that prints the numbers 1 to 3 from a flow can be rewritten as follows :
278
278
279
279
``` kotlin
280
280
import kotlinx.coroutines.*
@@ -301,17 +301,18 @@ fun main() = runBlocking<Unit> {
301
301
302
302
## Intermediate flow operators
303
303
304
- Flows can be transformed with operators, just as you would with collections and sequences.
304
+ Flows can be transformed using operators, in the same way as you would transform collections and
305
+ sequences.
305
306
Intermediate operators are applied to an upstream flow and return a downstream flow.
306
307
These operators are cold, just like flows are. A call to such an operator is not
307
308
a suspending function itself. It works quickly, returning the definition of a new transformed flow.
308
309
309
310
The basic operators have familiar names like [ map] and [ filter] .
310
- The important difference to sequences is that blocks of
311
+ An important difference of these operators from sequences is that blocks of
311
312
code inside these operators can call suspending functions.
312
313
313
314
For example, a flow of incoming requests can be
314
- mapped to the results with the [ map] operator, even when performing a request is a long-running
315
+ mapped to its results with a [ map] operator, even when performing a request is a long-running
315
316
operation that is implemented by a suspending function:
316
317
317
318
``` kotlin
@@ -337,7 +338,7 @@ fun main() = runBlocking<Unit> {
337
338
>
338
339
{type="note"}
339
340
340
- It produces the following three lines, each line appearing after each second :
341
+ It produces the following three lines, each appearing one second after the previous :
341
342
342
343
``` text
343
344
response 1
@@ -593,7 +594,7 @@ Since `simple().collect` is called from the main thread, the body of `simple`'s
593
594
This is the perfect default for fast-running or asynchronous code that does not care about the execution context and
594
595
does not block the caller.
595
596
596
- ### Wrong emission withContext
597
+ ### A common pitfall when using withContext
597
598
598
599
However, the long-running CPU-consuming code might need to be executed in the context of [ Dispatchers.Default] and UI-updating
599
600
code might need to be executed in the context of [ Dispatchers.Main] . Usually, [ withContext] is used
@@ -1012,8 +1013,8 @@ We get quite a different output, where a line is printed at each emission from e
1012
1013
1013
1014
## Flattening flows
1014
1015
1015
- Flows represent asynchronously received sequences of values, so it is quite easy to get in a situation where
1016
- each value triggers a request for another sequence of values. For example, we can have the following
1016
+ Flows represent asynchronously received sequences of values, and so it is quite easy to get into a situation
1017
+ where each value triggers a request for another sequence of values. For example, we can have the following
1017
1018
function that returns a flow of two strings 500 ms apart:
1018
1019
1019
1020
``` kotlin
@@ -1026,23 +1027,23 @@ fun requestFlow(i: Int): Flow<String> = flow {
1026
1027
1027
1028
<!-- - CLEAR -->
1028
1029
1029
- Now if we have a flow of three integers and call ` requestFlow ` for each of them like this:
1030
+ Now if we have a flow of three integers and call ` requestFlow ` on each of them like this:
1030
1031
1031
1032
``` kotlin
1032
1033
(1 .. 3 ).asFlow().map { requestFlow(it) }
1033
1034
```
1034
1035
1035
1036
<!-- - CLEAR -->
1036
1037
1037
- Then we end up with a flow of flows (` Flow<Flow<String>> ` ) that needs to be _ flattened_ into a single flow for
1038
+ Then we will end up with a flow of flows (` Flow<Flow<String>> ` ) that needs to be _ flattened_ into a single flow for
1038
1039
further processing. Collections and sequences have [ flatten] [ Sequence.flatten ] and [ flatMap] [ Sequence.flatMap ]
1039
1040
operators for this. However, due to the asynchronous nature of flows they call for different _ modes_ of flattening,
1040
- as such, there is a family of flattening operators on flows.
1041
+ and hence, a family of flattening operators on flows exists .
1041
1042
1042
1043
### flatMapConcat
1043
1044
1044
- Concatenating mode is implemented by [ flatMapConcat] and [ flattenConcat] operators. They are the most direct
1045
- analogues of the corresponding sequence operators. They wait for the inner flow to complete before
1045
+ Concatenation of flows of flows is provided by the [ flatMapConcat] and [ flattenConcat] operators. They are the
1046
+ most direct analogues of the corresponding sequence operators. They wait for the inner flow to complete before
1046
1047
starting to collect the next one as the following example shows:
1047
1048
1048
1049
``` kotlin
@@ -1058,7 +1059,7 @@ fun requestFlow(i: Int): Flow<String> = flow {
1058
1059
fun main () = runBlocking<Unit > {
1059
1060
// sampleStart
1060
1061
val startTime = System .currentTimeMillis() // remember the start time
1061
- (1 .. 3 ).asFlow().onEach { delay(100 ) } // a number every 100 ms
1062
+ (1 .. 3 ).asFlow().onEach { delay(100 ) } // emit a number every 100 ms
1062
1063
.flatMapConcat { requestFlow(it) }
1063
1064
.collect { value -> // collect and print
1064
1065
println (" $value at ${System .currentTimeMillis() - startTime} ms from start" )
@@ -1087,7 +1088,7 @@ The sequential nature of [flatMapConcat] is clearly seen in the output:
1087
1088
1088
1089
### flatMapMerge
1089
1090
1090
- Another flattening mode is to concurrently collect all the incoming flows and merge their values into
1091
+ Another flattening operation is to concurrently collect all the incoming flows and merge their values into
1091
1092
a single flow so that values are emitted as soon as possible.
1092
1093
It is implemented by [ flatMapMerge] and [ flattenMerge] operators. They both accept an optional
1093
1094
` concurrency ` parameter that limits the number of concurrent flows that are collected at the same time
@@ -1141,9 +1142,9 @@ The concurrent nature of [flatMapMerge] is obvious:
1141
1142
1142
1143
### flatMapLatest
1143
1144
1144
- In a similar way to the [ collectLatest] operator, that was shown in
1145
- [ "Processing the latest value"] ( #processing-the-latest-value ) section , there is the corresponding "Latest"
1146
- flattening mode where a collection of the previous flow is cancelled as soon as new flow is emitted.
1145
+ In a similar way to the [ collectLatest] operator, that was described in the section
1146
+ [ "Processing the latest value"] ( #processing-the-latest-value ) , there is the corresponding "Latest"
1147
+ flattening mode where the collection of the previous flow is cancelled as soon as new flow is emitted.
1147
1148
It is implemented by the [ flatMapLatest] operator.
1148
1149
1149
1150
``` kotlin
@@ -1184,9 +1185,11 @@ The output here in this example is a good demonstration of how [flatMapLatest] w
1184
1185
1185
1186
<!-- - TEST ARBITRARY_TIME -->
1186
1187
1187
- > Note that [ flatMapLatest] cancels all the code in its block (` { requestFlow(it) } ` in this example) on a new value.
1188
+ > Note that [ flatMapLatest] cancels all the code in its block (` { requestFlow(it) } ` in this example when a new value
1189
+ > is received.
1188
1190
> It makes no difference in this particular example, because the call to ` requestFlow ` itself is fast, not-suspending,
1189
- > and cannot be cancelled. However, it would show up if we were to use suspending functions like ` delay ` in there.
1191
+ > and cannot be cancelled. However, a differnce in output would be visible if we were to use suspending functions
1192
+ > like ` delay ` in ` requestFlow ` .
1190
1193
>
1191
1194
{type="note"}
1192
1195
0 commit comments