Coroutine used in the Android (a): Getting The Background

Original author: Sean McQuillan

原文地址: Coroutines on Android (part I): Getting the background

Translator: Bing heart says

This is a series of articles on the use of coroutines in Android. Benpian Let's take a look at how coroutine works and how it solves the problem.

Coroutine solve the problem?

Kotlin of coroutines (coroutine) brings a new approach to concurrency, on Android, it can be used to simplify asynchronous code. Although only bring stability Kotlin 1.3 version of the coroutine, but since the birth of programming languages, the concept of coroutines had appeared. The first use of coroutines language was released in 1967, Simula .

In the past few years, it coroutines is becoming increasingly popular. Many popular programming languages have joined the Association process, such as Javascript , C # , Python , Ruby , Go , and so on. Kotlin coroutine based on past building large-scale applications of established concepts.

In Andrews, the coroutine good solution to two problems:

  1. Time-consuming task , run too long blocked the main thread
  2. The main thread safe , allowing you to call any suspend the main thread (hang) function

Let us understand how coroutine help us build cleaner code!

Time-consuming tasks

Get pages and API interact, are related to the network request. Similarly, the data read from the database, load pictures from your hard drive, are related to the document read. These are what we call the time-consuming task, App impossible specially pause and wait for them to complete execution.

And network requests compared, it is difficult to imagine modern smartphone specific how fast code execution. Pixel 2Of no more than one CPU clock cycle 0.0000000004seconds, which is a number that a human is difficult to understand. But if you put a time-consuming network requests imagine a blink of an eye, about 0.4 s, which is well understood in the end how fast the CPU execution. Within a blink of time, or a slow network request, the CPU may execute over a million clock cycles.

In Android, each app has a main thread responsible for handling UI (View drawing for example) and user interaction. If the handle too many tasks in the main thread, the application will become Caton and brought a bad user experience. Any time-consuming task should not block the main thread,

To avoid network requests in the main thread, a common pattern is used CallBack(callback), which can enter your code callback certain period of time in the future. Access callback developer.android.comas follows:

class ViewModel: ViewModel() {
   fun fetchDocs() {
       get("developer.android.com") { result ->
           show(result)
       }
    }
}

Although the get()method is invoked on the main thread, but it will be a network request in another thread. Once the results are available a network request, the callback will be called in the main thread. This is a good way to deal with time-consuming tasks, like Retrofit can help you make a network request and does not block the main thread.

Use coroutine process time-consuming task

Treated with coroutine consuming tasks can be simplified code. To the above fetchDocs()method, for example, we use the coroutine to rewrite the callback logic before.

// Dispatchers.Main
suspend fun fetchDocs() {
    // Dispatchers.IO
    val result = get("developer.android.com")
    // Dispatchers.Main
    show(result)
}
// look at this in the next section
suspend fun get(url: String) = withContext(Dispatchers.IO){/*...*/}

The above code will block the main thread do? It is how to get the case without waiting for a network request to suspend or block the main thread get()return value? Facts have proved that, Kotlin code execution coroutine provides a way never block the main thread.

Coroutine added two operations to build some general features. In addition to invoke(or call)and return, it adds extra suspend(挂起)and resume(恢复).

  • Suspend - suspends the current coroutine execution, save all local variables
  • Resume - continue to be suspended from place to hang coroutine

In Kotlin, add to the function by suspendkeyword to implement this feature. You can only call the Suspend function Suspend function, or by coroutine constructor, for example launch, to open a new coroutine.

Suspend and resume work together to replace a callback.

In the example above, get()the method is performed prior to network requests hang coroutine, it is also responsible for a network request. Then, when the end of a network request, it only need to resume a suspended coroutine before, instead of calling a callback function to notify the main thread.

2466095-5751f567dc967ca5
image

Look at fetchDocsis how to implement it, you will understand how to suspend the works. Regardless of when a coroutine is suspended, its current stack frame (and variables to track function is running) will be copied and saved. When the resume, before the stack frame to be copied from the saved place to come back and re-run. In the middle part of the animation above, when all the coroutine on the main thread is suspended, it is time to update the UI, handling user events. In short, instead of the suspend and resume callbacks, quite neat!

When all the coroutine on the main thread is suspended, it would have time to do other things.

Even if we direct the order to write the code, it looks like the network will lead to blockage of the same request, but will press the coroutine execution as we had hoped, do not block the main thread.

Now, let's look at how to do coroutine is the main thread safe, and explore disaptchers(调度器).

The main thread safe coroutines

In Kotlin Association process, well-written suspend function call is always safe in the main thread. No matter what has been done suspend function, any thread should always be allowed to call them.

However, Android applications, if we put a lot of work to do on the main thread will cause APP to run slowly, such as network requests, JSON parsing, database read and write, and even navigate a large collection. Any one of them would cause the application Caton, degrade the user experience. So they should not run in the main thread.

Using suspend does not mean that we must tell Kotlin run function in a background thread. It is worth mentioning that the coroutine often run in the main thread. In fact, when you start a coroutine in response to user events, using Dispatchers.Main.immediate is a good idea.

Coroutine will run in the main thread, suspend does not necessarily mean running in the background.

In order for a function does not slow down the main thread, we can tell Kotlin coroutine use Defaultor IOscheduler. In Kotlin, all coroutine need to use a scheduler, even when they run in the main thread. Coroutine can hang themselves, and the scheduler is used to tell how they resume running.

To specify where to run coroutine, Kotlin provides Dispatchers to handle thread scheduling.

+-----------------------------------+
|         Dispatchers.Main          |
+-----------------------------------+
| Main thread on Android, interact  |
| with the UI and perform light     |
| work                              |
+-----------------------------------+
| - Calling suspend functions       |
| - Call UI functions               |
| - Updating LiveData               |
+-----------------------------------+

+-----------------------------------+
|          Dispatchers.IO           |
+-----------------------------------+
| Optimized for disk and network IO |
| off the main thread               |
+-----------------------------------+
| - Database*                       |
| - Reading/writing files           |
| - Networking**                    |
+-----------------------------------+

+-----------------------------------+
|        Dispatchers.Default        |
+-----------------------------------+
| Optimized for CPU intensive work  |
| off the main thread               |
+-----------------------------------+
| - Sorting a list                  |
| - Parsing JSON                    |
| - DiffUtils                       |
+-----------------------------------+
  • Room you use Suspend function , RxJava , LiveData provided automatically when the main thread safe.

  • Retrofit and Volley and other network management framework generally own thread scheduling, when you use Kotlin coroutine main thread does not need to explicitly guarantee safety.

Continue the example above, let's use the scheduler to define the get function. In vivo methods get function withContext(Dispatchers.IO)defined block of code, the code block in the scheduler Dispatchers.IOoperation. The method of any code block will always run in the IO scheduler. Due withContextitself is a suspend function, so it provides the main thread safe by coroutine.

// Dispatchers.Main
suspend fun fetchDocs() {
    // Dispatchers.Main
    val result = get("developer.android.com")
    // Dispatchers.Main
    show(result)
}
// Dispatchers.Main
suspend fun get(url: String) =
    // Dispatchers.IO
    withContext(Dispatchers.IO) {
        // Dispatchers.IO
        /* perform blocking network IO here */
    }
    // Dispatchers.Main

By coroutine, you can fine-grained control thread scheduling, because withContextso you can control any line of code to run on any thread, rather than the introduction of a callback to get the result. You can be applied in very small functions, such as network requests and database operations. Therefore, a better approach is to use withContextto ensure the implementation of each function is safe on any scheduler, including Main, so the caller when calling the function does not need to consider what should be run on a thread.

Well-written suspend function is invoked any thread should be safe.

Suspend function to ensure that each main thread safety is undoubtedly a good idea, if it is designed to any disk, network, or CPU-intensive tasks, use withContext to ensure that the main thread calls is safe. It is also based on design patterns coroutine library followed. If your entire code base will follow this principle, your code will be easier, threading issues and program logic will no longer be mixed. Coroutine free to start from the main thread, database and network request code will be easier, and can ensure the user experience.

withContext performance

For the main thread to provide security, withContext and callback or RxJava as fast. In some cases, you may even be used to optimize the coroutine context withContext callback. If a database function will call 10 times, you can tell Kotlin called once to switch on the outside of withContext in. Despite repeated calls to the database it will withContext, but he will be in the same scheduler, looking for the fastest route. In addition, Dispatchers.Defaultand Dispatchers.IOcoroutine switching between has been optimized in order to avoid possible thread switch.

What’s next

In this article we explore the coroutine to solve the problem. Coroutine programming language is a very old concept, since they can make the code easier to interact with the network, so recently become more popular.

On Android, you can use the coroutine solve two common problems:

  • Simplify the code consuming tasks such as network requests, disk access, even a large number of analytical JSON
  • Provide accurate main thread safe, promise not to block the main thread in the code will not make the situation even more bloated

In the next article, we will explore how they adapt to Android in order to keep track of all the work you started from the screen! (In the next post we'll explore how they fit in on Android to keep track of all the work you started from a screen!)

Translator says: feel a little translation of the disaster, but the disaster have to translate it, right when learning the English!

Articles starting micro-channel public number: 秉心说focused Java, Android original knowledge sharing, LeetCode problem solution.

More JDK source resolution, scan code concerned about me!

2466095-c66e723fd1d2c1ad
image

Guess you like

Origin blog.csdn.net/weixin_33744141/article/details/90991241