@@ -84,7 +84,7 @@ different UI application libraries:
8484* [ kotlinx-coroutines-swing] ( kotlinx-coroutines-swing ) -- ` Swing ` context for Swing UI applications.
8585
8686This guide covers all UI libraries simultaneously, because each of these modules consists of just one
87- object definition that is couple of pages long. You can use any of them as an example to write the corresponding
87+ object definition that is a couple of pages long. You can use any of them as an example to write the corresponding
8888context object for your favourite UI library, even if it is not included out of the box here.
8989
9090## Table of contents
@@ -111,9 +111,9 @@ context object for your favourite UI library, even if it is not included out of
111111
112112## Setup
113113
114- The runnable examples in this guide are be presented for JavaFx. The advantage is that all the examples can
114+ The runnable examples in this guide are presented for JavaFx. The advantage is that all the examples can
115115be directly started on any OS without the need for emulators or anything like that and they are fully self-contained
116- (all code is in one file).
116+ (each example is in one file).
117117There are separate notes on what changes need to be made (if any) to reproduce them on Android.
118118
119119### JavaFx
@@ -145,17 +145,17 @@ experiment with them by making changes.
145145Follow the guide on [ Getting Started With Android and Kotlin] ( https://kotlinlang.org/docs/tutorials/kotlin-android.html )
146146to create Kotlin project in Android Studio. You are also encouraged to add
147147[ Kotlin Android Extensions] ( https://kotlinlang.org/docs/tutorials/android-plugin.html )
148- to you application.
148+ to your application.
149149
150150In Android Studio 2.3 you'll get an application that looks similarly to the one shown below:
151151
152152![ UI example for Android] ( ui-example-android.png )
153153
154- Go the ` context_main.xml ` of your application and assign an ID of "hello" to the text view with "Hello World!" string,
154+ Go to the ` context_main.xml ` of your application and assign an ID of "hello" to the text view with "Hello World!" string,
155155so that it is available in your application as ` hello ` with Kotlin Android extensions. The pinkish floating
156156action button is already named ` fab ` in the project template that gets created.
157157
158- In the ` MainActivity.kt ` of you application remove the block ` fab.setOnClickListener { ... } ` and instead
158+ In the ` MainActivity.kt ` of your application remove the block ` fab.setOnClickListener { ... } ` and instead
159159add ` setup(hello, fab) ` invocation as the last line of ` onCreate ` function.
160160Create a placeholder ` setup ` function at the end of the file.
161161That is where various code is placed in the rest of this guide:
@@ -203,7 +203,7 @@ import kotlinx.coroutines.experimental.javafx.JavaFx as UI
203203
204204<!-- - CLEAR -->
205205
206- Coroutines confined to UI thread can freely update anything in UI and suspend without blocking the UI thread.
206+ Coroutines confined to the UI thread can freely update anything in UI and suspend without blocking the UI thread.
207207For example, we can perform animations by coding them in imperative style. The following code updates the
208208text with a 10 to 1 countdown twice a second, using [ launch] coroutine builder:
209209
@@ -231,7 +231,7 @@ while `delay` waits, because it does not block the UI thread -- it just suspends
231231### Cancel UI coroutine
232232
233233We can keep a reference to the [ Job] object that ` launch ` function returns and use it to cancel
234- coroutine when want to stop it. Let us cancel the coroutine when pinkish circle is clicked:
234+ coroutine when we want to stop it. Let us cancel the coroutine when pinkish circle is clicked:
235235
236236``` kotlin
237237fun setup (hello : Text , fab : Circle ) {
@@ -286,13 +286,13 @@ fun setup(hello: Text, fab: Circle) {
286286<!-- - INCLUDE .*/example-ui-actor-([0-9]+).kt -->
287287
288288Our first implementation for ` onClick ` just launches a new coroutine on each mouse event and
289- passes the corresponding mouse event into the block (just in case we need it):
289+ passes the corresponding mouse event into the supplied action (just in case we need it):
290290
291291``` kotlin
292- fun Node.onClick (block : suspend (MouseEvent ) -> Unit ) {
292+ fun Node.onClick (action : suspend (MouseEvent ) -> Unit ) {
293293 onMouseClicked = EventHandler { event ->
294294 launch(UI ) {
295- block (event)
295+ action (event)
296296 }
297297 }
298298}
@@ -308,10 +308,10 @@ update the text. Try it. It does not look very good. We'll fix it later.
308308 on Android, so it is omitted.
309309
310310``` kotlin
311- fun View.onClick (block : suspend () -> Unit ) {
311+ fun View.onClick (action : suspend () -> Unit ) {
312312 setOnClickListener {
313313 launch(UI ) {
314- block ()
314+ action ()
315315 }
316316 }
317317}
@@ -323,15 +323,15 @@ fun View.onClick(block: suspend () -> Unit) {
323323
324324We can cancel an active job before starting a new one to ensure that at most one coroutine is animating
325325the countdown. However, it is generally not the best idea. The [ cancel] [ Job.cancel ] function serves only as a signal
326- to abort coroutine. Cancellation is cooperative and coroutine may, at the moment, be doing something non-cancellable
326+ to abort a coroutine. Cancellation is cooperative and a coroutine may, at the moment, be doing something non-cancellable
327327or otherwise ignore a cancellation signal. A better solution is to use an [ actor] for tasks that should
328328not be performed concurrently. Let us change ` onClick ` extension implementation:
329329
330330``` kotlin
331- fun Node.onClick (block : suspend (MouseEvent ) -> Unit ) {
331+ fun Node.onClick (action : suspend (MouseEvent ) -> Unit ) {
332332 // launch one actor to handle all events on this node
333333 val eventActor = actor<MouseEvent >(UI ) {
334- for (event in channel) block (event) // pass event to block
334+ for (event in channel) action (event) // pass event to action
335335 }
336336 // install a listener to offer events to this actor
337337 onMouseClicked = EventHandler { event ->
@@ -344,7 +344,7 @@ fun Node.onClick(block: suspend (MouseEvent) -> Unit) {
344344
345345The key idea that underlies an integration of an actor coroutine and a regular event handler is that
346346there is an [ offer] [ SendChannel.offer ] function on [ SendChannel] that does not wait. It sends an element to the actor immediately,
347- if it is possible, or discards an element otherwise. An ` offser ` actually returns a ` Boolean ` result which we ignore here.
347+ if it is possible, or discards an element otherwise. An ` offer ` actually returns a ` Boolean ` result which we ignore here.
348348
349349Try clicking repeatedly on a circle in this version of the code. The clicks are just ignored while the countdown
350350animation is running. This happens because the actor is busy with an animation and does not receive from its channel.
@@ -355,10 +355,10 @@ the `receive` is active.
355355 The corresponding extension for ` View ` class looks like this:
356356
357357``` kotlin
358- fun View.onClick (block : suspend () -> Unit ) {
358+ fun View.onClick (action : suspend () -> Unit ) {
359359 // launch one actor
360360 val eventActor = actor<Unit >(UI ) {
361- for (event in channel) block ()
361+ for (event in channel) action ()
362362 }
363363 // install a listener to activate this actor
364364 setOnClickListener {
@@ -377,14 +377,14 @@ processing the previous one. The [actor] coroutine builder accepts an optional
377377controls the implementation of the channel that this actor is using for its mailbox. The description of all
378378the available choices is given in documentation of the [ Channel()] [ Channel.invoke ] factory function.
379379
380- Let us change to the code to use [ ConflatedChannel] by passing [ Channel.CONFLATED] capacity value. The
380+ Let us change the code to use [ ConflatedChannel] by passing [ Channel.CONFLATED] capacity value. The
381381change is only to the line that creates an actor:
382382
383383``` kotlin
384- fun Node.onClick (block : suspend (MouseEvent ) -> Unit ) {
384+ fun Node.onClick (action : suspend (MouseEvent ) -> Unit ) {
385385 // launch one actor to handle all events on this node
386386 val eventActor = actor<MouseEvent >(UI , capacity = Channel .CONFLATED ) { // <--- Changed here
387- for (event in channel) block (event) // pass event to block
387+ for (event in channel) action (event) // pass event to action
388388 }
389389 // install a listener to offer events to this actor
390390 onMouseClicked = EventHandler { event ->
@@ -410,21 +410,21 @@ events. In this case, the animation runs as many times and the circle is clicked
410410
411411## Blocking operations
412412
413- This section explains patterns on using UI coroutines with thread-blocking operations.
413+ This section explains how to use UI coroutines with thread-blocking operations.
414414
415415### The problem of UI freezes
416416
417- It would have been great if all APIs out there were written as suspending functions that never block an
417+ It would have been great if all APIs out there were written as suspending functions that never blocks an
418418execution thread. However, it is quite often not the case. Sometimes you need to do a CPU-consuming computation
419419or just need to invoke some 3rd party APIs for network access, for example, that blocks the invoker thread.
420- You can cannot do that from the UI thread nor from them UI-confined coroutine directly, because that would
420+ You cannot do that from the UI thread nor from the UI-confined coroutine directly, because that would
421421block the UI thread and cause the freeze up of the UI.
422422
423423<!-- - INCLUDE .*/example-ui-blocking-([0-9]+).kt
424424
425- fun Node.onClick(block : suspend (MouseEvent) -> Unit) {
425+ fun Node.onClick(action : suspend (MouseEvent) -> Unit) {
426426 val eventActor = actor<MouseEvent>(UI, capacity = Channel.CONFLATED) {
427- for (event in channel) block (event) // pass event to block
427+ for (event in channel) action (event) // pass event to action
428428 }
429429 onMouseClicked = EventHandler { event ->
430430 eventActor.offer(event)
@@ -457,7 +457,7 @@ fun setup(hello: Text, fab: Circle) {
457457 delay(100 ) // update the text every 100ms
458458 }
459459 }
460- // compute next fibonacci number of each click
460+ // compute the next fibonacci number of each click
461461 var x = 1
462462 fab.onClick {
463463 result = " fib($x ) = ${fib(x)} "
@@ -479,7 +479,7 @@ The fix for the blocking operations on the UI thread is quite straightforward wi
479479convert our "blocking" ` fib ` function to a non-blocking suspending function that runs the computation in
480480the background thread by using [ run] function to change its execution context to [ CommonPool] of background
481481threads. Notice, that ` fib ` function is now marked with ` suspend ` modifier. It does not block the coroutine that
482- it is invoked from anymore, but suspends its execution when the computation in background thread is working:
482+ it is invoked from anymore, but suspends its execution when the computation in the background thread is working:
483483
484484<!-- - INCLUDE .*/example-ui-blocking-0[23].kt
485485
@@ -514,8 +514,8 @@ You can run this code and verify that UI is not frozen while large Fibonacci num
514514However, this code computes ` fib ` somewhat slower, because every recursive call to ` fib ` goes via ` run ` . This is
515515not a big problem in practice, because ` run ` is smart enough to check that the coroutine is already running
516516in the required context and avoids overhead of dispatching coroutine to a different thread again. It is an
517- overhead nonetheless, which is visible on this primitive code that does nothing else of use , but only adds integers
518- in between invocations to ` run ` . For some more substantial code, the overhead of an extra ` run ` invocation is
517+ overhead nonetheless, which is visible on this primitive code that does nothing else, but only adds integers
518+ in between invocations to ` run ` . For some more substantial code, the overhead of an extra ` run ` invocation is
519519not going to be significant.
520520
521521Still, this particular ` fib ` implementation can be made to run as fast as before, but in the background thread, by renaming
@@ -532,11 +532,11 @@ fun fibBlocking(x: Int): Int =
532532
533533> You can get full code [ here] ( kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-blocking-03.kt ) .
534534
535- You can now enjoy full-speed naive Fibonacci computation without blocking UI thread. All we need is ` run(CommonPool) ` .
535+ You can now enjoy full-speed naive Fibonacci computation without blocking the UI thread. All we need is ` run(CommonPool) ` .
536536
537- Note, that because the ` fib ` function is invoked from a single actor in our code, there is at most one concurrent
537+ Note, that because the ` fib ` function is invoked from the single actor in our code, there is at most one concurrent
538538computation of it at any given time, so this code has a natural limit on the resource utilization.
539- It can saturate at most on CPU core at any given time .
539+ It can saturate at most one CPU core.
540540
541541## Lifecycle
542542
@@ -546,15 +546,15 @@ This section outlines an approach to life-cycle management with coroutines.
546546
547547A typical UI application has a number of elements with a lifecycle. Windows, UI controls, activities, views, fragments
548548and other visual elements are created and destroyed. A long-running coroutine, performing some IO or a background
549- computation, can retain reference to the corresponding UI elements for longer than it is needed, preventing garbage
549+ computation, can retain references to the corresponding UI elements for longer than it is needed, preventing garbage
550550collection of the whole trees of UI objects that were already destroyed and will not be displayed anymore.
551551
552552The natural solution to this problem is to associate a [ Job] object with each UI object that has a lifecycle and create
553553all the coroutines in the context of this job.
554554
555555For example, in Android application an ` Activity ` is initially _ created_ and is _ destroyed_ when it is no longer
556556needed and when its memory must be released. A natural solution is to attach an
557- instance of ` Job ` to an instance of ` Activity ` . We can create a mini-framework for that,
557+ instance of a ` Job ` to an instance of an ` Activity ` . We can create a mini-framework for that,
558558by defining the following ` JobHolder ` interface:
559559
560560``` kotlin
@@ -568,7 +568,7 @@ its `onDestroy` function to cancel the corresponding job:
568568
569569``` kotlin
570570class MainActivity : AppCompatActivity (), JobHolder {
571- override val job: Job = Job () // an instance of Job for this activity
571+ override val job: Job = Job () // the instance of a Job for this activity
572572
573573 override fun onDestroy () {
574574 super .onDestroy()
@@ -580,7 +580,7 @@ class MainActivity : AppCompatActivity(), JobHolder {
580580```
581581
582582We also need a convenient way to retrieve a job for any view in the application. This is straightforward, because
583- an activity is a context of the views in it, so we can define the following ` View.contextJob ` extension property:
583+ an activity is an Android ` Context ` of the views in it, so we can define the following ` View.contextJob ` extension property:
584584
585585``` kotlin
586586val View .contextJob: Job
@@ -590,17 +590,17 @@ val View.contextJob: Job
590590Here we use [ NonCancellable] implementation of the ` Job ` as a null-object for the case where our ` contextJob `
591591extension property is invoked in a context that does not have an attached job.
592592
593- As convenience of having a ` contextJob ` available is that we can simply use it to start all the coroutines
593+ A convenience of having a ` contextJob ` available is that we can simply use it to start all the coroutines
594594without having to worry about explicitly maintaining a list of the coroutines we had started.
595595All the life-cycle management will be taken care of by the mechanics of parent-child relations between jobs.
596596
597597For example, ` View.onClick ` extension from the previous section can now be defined using ` contextJob ` :
598598
599599``` kotlin
600- fun View.onClick (block : suspend () -> Unit ) {
601- // launch one actor as a paren of the context job
600+ fun View.onClick (action : suspend () -> Unit ) {
601+ // launch one actor as a parent of the context job
602602 val eventActor = actor<Unit >(contextJob + UI , capacity = Channel .CONFLATED ) {
603- for (event in channel) block ()
603+ for (event in channel) action ()
604604 }
605605 // install a listener to activate this actor
606606 setOnClickListener {
@@ -609,10 +609,10 @@ fun View.onClick(block: suspend () -> Unit) {
609609}
610610```
611611
612- Notice ` contextJob + UI ` expression that is used to start an actor in the above code. It defines a coroutine context
613- for our new actor that includes the job and UI dispatcher. The coroutine that is started by this
612+ Notice how ` contextJob + UI ` expression is used to start an actor in the above code. It defines a coroutine context
613+ for our new actor that includes the job and the ` UI ` dispatcher. The coroutine that is started by this
614614` actor(contextJob + UI) ` expression is going to become a child of the job of the corresponding context. When the
615- activity is destroyed and its job is cancelled, all its children coroutines are cancelled.
615+ activity is destroyed and its job is cancelled all its children coroutines are cancelled, too .
616616
617617Parent-child relation between jobs forms a hierarchy. A coroutine that performs some background job on behalf of
618618the view and in its context can create further children coroutines. The whole tree of coroutines gets cancelled
0 commit comments