Using kotlin’s coprocess to realize simple asynchronous loading

preface

As we all know, in Android, when the execution time of the program exceeds 5 seconds, it will cause anr and cause the program to crash. Since the UI update operation is carried out in the UI main thread, in the ideal state, when displaying 60 frames per second, the human eye can not feel the Caton, 1000ms / 60 frames, that is, the drawing time of each frame should not exceed 16.67ms. If an operation takes longer than this value, the UI will get stuck. Therefore, in actual development, I usually put time-consuming operations in a new thread (such as obtaining data from the network, reading pictures from SD card, etc.), but in Android, UI updates can only be updated in the UI main thread. Therefore, when we perform some operations in non UI threads, we need to communicate with the UI main thread to update the UI. In Android, Google provides us with tools such as asynctask and handler to facilitate the communication between threads. Many third-party libraries have also implemented this function for us, such as the very popular rxjava library. In this article, I want to share with you that kotlin's coroutine (collaborative process) is used to realize the asynchronous loading of time-consuming operations. Now there are rxjava, so it is necessary to understand the asynchronous related operations in kotlin, which is now the official development language of Android. This article only explains the basic usage of coroutine and does not go deep into the underlying research. I will show you the basic usage of coroutine with an example of loading pictures.

Initial configuration before using coroutine

First, we use Android studio to create a new project, and check [include kotlin support] when creating a new project, as shown below

After the project is created successfully, we need to add the following configuration under the Android configuration module in the build.gradle file

Then add the following dependencies to the build. Gradle file

The complete configuration is as follows:

After the above steps, the configuration of coroutine has been completed. Then we can use coroutine.

Implement your first coroutine program

Now let's start writing our first coroutine example program. The main function of this program is to load a picture from mobile media and display it in an ImageView. Let's take a look at the code of loading pictures in synchronization before coroutine is used, as follows:

In the code above, we read an image from the media and convert it into a bitmap object. Because this is a IO operation, if we call this code in the main thread of UI, it may cause the program to Catton or generate ANR crash, so we need to call the following code in the newly opened thread.

Then we need to call the following code in the UI thread to display the loaded pictures.

In order to achieve this function, in traditional Android programs, we need to use handler or asynctask to send the results from the non UI main thread to the UI main thread for display. We need to write a lot of additional code. And the readability of these codes is not very friendly. Next, let's take a look at the code that uses kotlin's coroutine to load images, as follows:

Let's ignore the return value job first. We will introduce it later. Here, we are concerned about the launch function and the parameter background and UI. The only difference from the previous method of loading pictures synchronously is that we call the lauch function here. Lauch () creates and starts a collaboration. The parameter background here is a coroutinecontext object, which ensures that the collaboration runs in a background thread and that your application will not block and crash due to time-consuming operations. You can define a coroutinecontext as follows:

He will use a thread pool with two threads to perform operations in the process. In the first collaboration, we call launch (UI) to create and start a new collaboration. The UI here is not created by ourselves. It is a coroutinecontext predefined by kotlin on the Android platform, which represents the execution of operations in the collaboration in the UI main thread. Therefore, we put the operation ImageView. Setimagebitmap (bitmap) of the update program interface into this collaboration. Through the example code here, you will find that using coprocedures in kotlin to realize inter thread communication and switching is very simple, which is simpler than rxjava. It looks like you write code that synchronizes.

Cancel collaboration

In the above example, we returned an object of job type. We can cancel a coroutine by calling job. Cancel(). For example, when we exit the current activity, the picture has not been loaded. At this point, we can call job.cancel () in onDestroy to cancel this unfinished task. This is the same as calling dispose () when using rxjava or cancel () when using asynctask to cancel the unfinished operation.

LifecycleObserver

Many very good things have been introduced into Android architecture components, such as ViewModel, room, livedata and lifecycle API. It gives us a very safe and easy way to monitor the life cycle changes of activities and fragments. Next, we will use them to improve the example of loading pictures before. We will use lifecycle to listen to the activity life cycle and make corresponding processing (the background task will be automatically cancelled when the activity calls ondestroy()).

We define the following code to use the collaboration process:

We also created an extension function of lifecycle owner:

There are many new things in this function. It doesn't matter if you seem confused. We will explain them step by step. We have extended a load function in all classes that implement the lifecycle owner interface. That is, when we use the support library, we can directly call this load function in the activity or fragment (appcompatactivity and fragment in the support library implement the lifecycle owner interface). In order to access lifecycle members in this function, we add coroutinelicyclelistener as an observer.

The load () function uses a lambda expression named loader as a parameter (this lambda expression returns a generic type T). In the load () function, we call a function named async, which is also used to create a collaboration. It uses background as the context. Note that the second parameter start = coroutinestart.lazy. It means that a collaborative process will not be started immediately. It won't start until the request you display returns a value. You'll see how to do it later. This coroutine returns a deferred < T > object to the caller. It is similar to the job object we mentioned earlier, but it can carry a delayed value, similar to promise in JavaScript or future < T > in Java APIs.

Next, we define an extension function then () of the deferred < T > class (the type we returned in the load function earlier), which also uses a lambda expression called block as an argument. This lambda expression takes an object of type T as an argument. The specific codes are as follows:

This function uses launch () to create another collaboration, which will run in the main thread of the program. In this new association, we call the lambda expression called block in the then function and use the await () function as its parameter. Await () is invoked in the main thread, but it will not block the execution of the main thread. It will suspend the function, and the main thread can continue to do other things. When the value is returned from other coroutines, it will wake up and pass the value from deferred to the lambda. Suspending functions is the most important concept in coroutines.

Once the ondestroy method of activity is called, the lifecycle observer we added in the load () function will cancel the first coroutine and the second coroutine to avoid block () being called.

Kotlin Coroutine DSL

We have defined two extension functions and a class for canceling co procedures. Let's see how to use them. The code is as follows:

In the code above, we pass a lambda to load () function. In this lambda, we call the loadBitmapFromMediaStore () function to run in a background process. Once the loadbitmapfrommediastore() function returns bitmap, the load() function will return deferred < bitmap >. The extended function then () is modified by infix, so when deferred < bitmap > returns, we can call it with the above strange syntax. The lambda we pass to then () will receive a bitmap object. Therefore, we can simply call ImageView. Setimagebitmap (it) to display this bitmap.

The above code can be applied to any other operation that needs to use asynchronous calls and forward values to the main thread. Kotlin's coroutine may not be as powerful as rxjava. However, kotlin's collaborative process is more readable and simpler. Now you can safely use it to perform your asynchronous operations without worrying about memory leaks. The following is an example of using the above code to load data from the network and display it:

The above is all the content to be shared in this article. I hope it can be helpful to you. If you find something wrong in the article, you are also welcome to help point out so that I can make timely corrections.

Source address: https://github.com/chenyi2013/CoroutineDemo (local download)

summary

The above is the whole content of this article. I hope the content of this article has a certain reference value for your study or work. If you have any questions, you can leave a message. Thank you for your support for programming tips.

Reference article:

https://developer.android.com/topic/libraries/architecture/lifecycle.html

https://kotlinlang.org/docs/reference/coroutines.html

https://hellsoft.se/simple-asynchronous-loading-with-kotlin-coroutines-f26408f97f46

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>