Skip to content

Commit 2fd7cb3

Browse files
committed
An example of cancellation via explicit job
1 parent 8c8551e commit 2fd7cb3

File tree

4 files changed

+89
-70
lines changed

4 files changed

+89
-70
lines changed

coroutines-guide.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ This is a short guide on core features of `kotlinx.coroutines` with a series of
5252
* [Children of a coroutine](#children-of-a-coroutine)
5353
* [Combining contexts](#combining-contexts)
5454
* [Naming coroutines for debugging](#naming-coroutines-for-debugging)
55+
* [Cancellation via explicit job](#cancellation-via-explicit-job)
5556
* [Channels](#channels)
5657
* [Channel basics](#channel-basics)
5758
* [Closing and iteration over channels](#closing-and-iteration-over-channels)
@@ -953,6 +954,55 @@ The output it produces with `-Dkotlinx.coroutines.debug` JVM option is similar t
953954
[main @main#1] The answer for v1 / v2 = 42
954955
```
955956

957+
### Cancellation via explicit job
958+
959+
Let us put our knowledge about contexts, children and jobs together. Assume that our application has
960+
an object with a lifecycle, but that object is not a coroutine. For example, we are writing an Android application
961+
and launch various coroutines in the context of an Android activity to perform asynchronous operations to fetch
962+
and update data, do animations, etc. All of these coroutines must be cancelled when activity is destroyed
963+
to avoid memory leaks.
964+
965+
We can manage a lifecycle of our coroutines by creating an instance of [Job] that is tied to
966+
the lifecycle of our activity. A job instance is created using [Job()][Job.invoke] factory function
967+
as the following example shows. We need to make sure that all the coroutines are started
968+
with this job in their context and then a single invocation of [Job.cancel] terminates them all.
969+
970+
```kotlin
971+
fun main(args: Array<String>) = runBlocking<Unit> {
972+
val job = Job() // create a job object to manage our lifecycle
973+
// now launch ten coroutines for a demo, each working for a different time
974+
val coroutines = List(10) { i ->
975+
// they are all children of our job object
976+
launch(context + job) { // we use the context of main runBlocking thread, but with our own job object
977+
delay(i * 200L) // variable delay 0ms, 200ms, 400ms, ... etc
978+
println("Coroutine $i is done")
979+
}
980+
}
981+
println("Launched ${coroutines.size} coroutines")
982+
delay(500L) // delay for half a second
983+
println("Cancelling job!")
984+
job.cancel() // cancel our job.. !!!
985+
delay(1000L) // delay for more to see if our coroutines are still working
986+
}
987+
```
988+
989+
> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-context-09.kt)
990+
991+
The output of this example is:
992+
993+
```
994+
Launched 10 coroutines
995+
Coroutine 0 is done
996+
Coroutine 1 is done
997+
Coroutine 2 is done
998+
Cancelling job!
999+
```
1000+
1001+
As you can see, only the first three coroutines had printed a message and the others were cancelled
1002+
by a single invocation of `job.cancel()`. So all we need to do in our hypothetical Android
1003+
application is to create a parent job object when activity is created, use it for child coroutines,
1004+
and cancel it when activity is destroyed.
1005+
9561006
## Channels
9571007

9581008
Deferred values provide a convenient way to transfer a single value between coroutines.
@@ -1299,7 +1349,9 @@ The first four elements are added to the buffer and the sender suspends when try
12991349
[Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/index.html
13001350
[Deferred.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/await.html
13011351
[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/index.html
1352+
[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/cancel.html
13021353
[Job.start]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/start.html
1354+
[Job.invoke]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/invoke.html
13031355
[NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-non-cancellable/index.html
13041356
[Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-unconfined/index.html
13051357
[CancellationException]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-cancellation-exception.html

kotlinx-coroutines-core/src/test/kotlin/examples/async-example.kt

Lines changed: 0 additions & 48 deletions
This file was deleted.

kotlinx-coroutines-core/src/test/kotlin/examples/log.kt

Lines changed: 0 additions & 22 deletions
This file was deleted.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2016-2017 JetBrains s.r.o.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
18+
package guide.context.example09
19+
20+
import kotlinx.coroutines.experimental.*
21+
22+
fun main(args: Array<String>) = runBlocking<Unit> {
23+
val job = Job() // create a job object to manage our lifecycle
24+
// now launch ten coroutines for a demo, each working for a different time
25+
val coroutines = List(10) { i ->
26+
// they are all children of our job object
27+
launch(context + job) { // we use the context of main runBlocking thread, but with our own job object
28+
delay(i * 200L) // variable delay 0ms, 200ms, 400ms, ... etc
29+
println("Coroutine $i is done")
30+
}
31+
}
32+
println("Launched ${coroutines.size} coroutines")
33+
delay(500L) // delay for half a second
34+
println("Cancelling job!")
35+
job.cancel() // cancel our job.. !!!
36+
delay(1000L) // delay for more to see if our coroutines are still working
37+
}

0 commit comments

Comments
 (0)