Coroutines

Context

Coroutines have to be run inside a context.

Suspend function

Suspend functions make sense to start only from coroutine (compilation requirements). And some functions (e.g. delay()) are making sense only inside of suspend functions.

Suspend function can be called from

  • another suspend function

  • from coroutine (This is the way actually to start a "first" suspend function)

Do not use blocking code (e.g. Thread.sleep()) in coroutine

Testing of suspend function

@Test
fun theTest() = runBlocking { // test should become a coroutine to be able to call suspend function
    doWork()    // assuming that doWork is a suspend function
    //assert bla
}

Builders

Launch

Launch creates a coroutine and submit it to the separate thread, main thread will not wait until the coroutine is finished.

runBlocking

This can be useful to use in tests (to make test a coroutine to be able to invoke suspend function in the test).

runBlocking is used as a bridge between regular and suspending functions, or between the blocking and non-blocking worlds. It works as an adaptor for starting the top-level main coroutine. It is intended primarily to be used in main() functions and tests.

async

async starts a new coroutine and returns a Deferred object. Deferred represents a concept known by other names such as Future or Promise. It stores a computation, but it defers the moment you get the final result; it promises the result sometime in the future.

The main difference between async and launch is that launch is used to start a computation that isn't expected to return a specific result. launch returns a Job that represents the coroutine. It is possible to wait until it completes by calling Job.join().

Deferred is a generic type that extends Job. An async call can return a Deferred<Int> or a Deferred<CustomType>, depending on what the lambda returns (the last expression inside the lambda is the result).

To get the result of a coroutine, you can call await() on the Deferred instance. While waiting for the result, the coroutine that this await() is called from is suspended:

Structured concurrency

The coroutine scope is responsible for the structure and parent-child relationships between different coroutines. New coroutines usually need to be started inside a scope.

When launch, async, or runBlocking are used to start a new coroutine, they automatically create the corresponding scope. All of these functions take a lambda with a receiver as an argument, and CoroutineScope is the implicit receiver type:

Control

Join

Similar to joining a thread. The calling thread blocks until coroutine is finished.

Launch returns Job, which has join method. We can also check is coroutine is finished.

Cancel

In order to be cancellable coroutine should be able to check for cancellation.

E.g. delay() function knows how to cancel.

It is possible to check the status itself (it did not work on my machine, but I took it from the course)

Last updated

Was this helpful?