1. Coroutine definition

To understand the relationship from an Android developer’s perspective:

  • All of our code runs in threads, and threads run in processes.
  • The coroutine is not directly tied to the operating system, but it is not a castle in the air. It also runs in threads, either single-threaded or multithreaded.
  • The total execution time of a coroutine in a single thread is no less than without it.
  • On Android, if a network request is made on the main thread, it is thrownNetworkOnMainThreadExceptionThis is also true for coroutines on the main thread, where the use of coroutines is thread cutting.

Coroutines are designed to solve concurrency problems and make collaborative multitasking easier to implement. I’ll leave the concept of “collaborative multitasking” out until we learn how to use it.

In the video, coroutines are a set of thread-wrapped apis from Kotlin, but that’s not to say that coroutines are made for threads.

2. What’s good about coroutines

We need to understand the concept of closure, which is often used when we call the API in Kotlin coroutines. Closures are not a new concept in Kotlin and have been supported since Java 8.

Let’s start with Thread as an example to see what a closure is:

// Create a full representation of Thread
Thread(object : Runnable {
    override fun run(a){... }})// satisfy SAM
Thread({
    ...
})

// Use closures to simplify to
Thread {
    ...
}
Copy the code

Like Thread {… } is a closure.

There is a syntactic sugar in Kotlin: when the last argument to a function is a lambda expression, the lambda can be written out of parentheses. That’s the closure principle.

Here a parameter of type Runnable is required, and Runnable is an interface that defines only one function run. This satisfies Kotlin’s SAM, which can be converted to passing a lambda expression (paragraph 2) because it is the last parameter, Following the closure principle we can write Thread {… } (paragraph 3).

The launch function used above can be simplified with closures:

🏝️
launch {
    ...
}
Copy the code

3. Basic use

The launch function is not a top-level function and cannot be used directly. There are three ways to create a coroutine:

🏝 ️// Use the runBlocking top-level function
runBlocking {
    getImage(imageId)
}

// Use a GlobalScope singleton
// 👇 can call launch directly to start coroutines
GlobalScope.launch {
    getImage(imageId)
}

// Create a CoroutineScope object via CoroutineContext
// 👇 requires a parameter of type CoroutineContext
val coroutineScope = CoroutineScope(context)
coroutineScope.launch {
    getImage(imageId)
}
Copy the code
  • Method one is typically used in unit testing scenarios, and is not used in business development because it is thread blocked.
  • Method two and userunBlockingThe difference is that the thread is not blocked. This is also not recommended in Android development, as it has the same lifecycle as the app and cannot be cancelled (what is cancelling a coroutine will be covered in a later article).
  • Method three is the more recommended method of use, we can passcontextParameters to manage and control the coroutine lifecycle (herecontextIt’s not the same thing as Android, it’s a more general concept, and there will be an Android platform wrapper to work with).