Example of Kotlin Coroutines asynchronous loading, kotlincoroutines

Source: Internet
Author: User

Example of Kotlin Coroutines asynchronous loading, kotlincoroutines

Preface

Kotlin Coroutines is a new asynchronous API launched by Kotlin. It is not the best solution to all problems, but it is expected to make things easier in many cases. Here we will only briefly show the specific usage of this library in Android. I won't talk much about it below. Let's take a look at the detailed introduction.

Introduction of Coroutines

// In the application build. add the following code to the android node in the gradle file: kotlin {experimental {coroutines 'enable'} // Add the following two lines to the dependency: implementation "org. jetbrains. kotlinx: kotlinx-coroutines-core: 0.20 "implementation" org. jetbrains. kotlinx: kotlinx-coroutines-android: 0.20"

Example of the first Coroutines

We usually load an image to the ImageView. the asynchronous loading task is as follows:

fun loadBitmapFromMediaStore(imageId: Int,         imagesBaseUri: Uri): Bitmap { val uri = Uri.withAppendedPath(imagesBaseUri, imageId.toString()) return MediaStore.Images.Media.getBitmap(contentResolver, uri)}

This method must be executed in the background thread, because it is an IO operation, which means there are many solutions to start background tasks. Once this method returns a bitmap, we need to display it in Imageview immediately.

imageView.setImageBitmap(bitmap)

This line of code must be executed in the main thread, otherwise it will crash.

If the above three lines of code are written together, the program will be stuck or rolled back, depending on the reasonable choice of thread. Next, let's take a look at how Coroutines using kotlin solves this problem:

val job = launch(Background) { val uri = Uri.withAppendedPath(imagesBaseUri, imageId.toString()) val bitmap = MediaStore.Images.Media.getBitmap(contentResolver,  launch(UI) { imageView.setImageBitmap(bitmap) }}

The most important here are launch () and the Background and UI parameters. launch () indicates creating and starting a Coroutine. The Background parameter CoroutineContext is used to ensure execution in the Background thread, to ensure that the application will not be stuck or crash, you can declare a CoroutineContext as shown below.

internal val Background = newFixedThreadPoolContext(2, "bg")

This creates a new context and uses two common threads when executing its tasks.

Next we will talk about launch (UI), which will trigger another coroutine and will be executed in Android
Main thread.

Canceled

The next challenge is to deal with things related to the Activity declaration cycle. When you load a task, you leave the Activity before the execution is complete, so that he is callingimageView.setImageBitmap(bitmap)Crash is triggered, so we need to cancel the task before leaving the activity. Here, the returned job of the launch () method is used. When the activity calls the onStop method, we need to use the job to cancel the task.

job.cancel()

This is like calling the dispose function when using Rxjava and the cancel function when using AsyncTask.

LifecycleObserver

Android Architecture Components provides many powerful libraries for Android Developers, one of which is the Lifecycle API. we provided a simple way to monitor the lifecycle of activity and fragment in real time. Let's define the code to be used with coroutines.

class CoroutineLifecycleListener(val deferred: Deferred<*>) : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun cancelCoroutine() { if (!deferred.isCancelled) {  deferred.cancel() } }}

We create a LifecycleOwner Extension function:

fun <T> LifecycleOwner.load(loader: () -> T): Deferred<T> { val deferred = async(context = Background,       start = CoroutineStart.LAZY) { loader() } lifecycle.addObserver(CoroutineLifecycleListener(deferred)) return deferred}

There are too many new things in this method. Next we will explain them one by one:

Now we can callload()And access the lifecycle members from the function, and add our CoroutineLifecycleListener as the observer.

The load method requires a loader as the parameter and returns a common type T. In the load method, we call the async () function of another Coroutine creator, the Background coroutine context will be used to execute tasks in the Background thread. Note that this method also has another parameter start = CoroutineStart. LAZY, which means that coroutine will not be executed immediately until it is called.

Coroutine then returnsDefered<T>Object To the caller, which is similar to our previous Job, but it can also carry a latency value, such as JavaScript Promise orFuture <T>Better, he has an await method.

Next we will define another extension function.then()This timeDeferen<T>The above definition is the type returned by the load method above. It also uses lambda as a parameter and name it block. It uses a single object of the T type as its parameter.

infix fun <T> Deferred<T>.then(block: (T) -> Unit): Job { return launch(context = UI) { block(this@then.await()) }}

This function will uselaunch()The function creates another Coroutine and runs on the main thread this time. The lambda (name block) passed to Coroutine uses the value of the finished Deferred object as its parameter. We callawait()Wait until the Deferred object returns a value.

This is how impressive coroutine is.await()The call is completed on the main thread, but it does not block further execution of the thread. It will simply pause the execution of the function until it is ready when it recovers and passes the latency value to lambda. When coroutine is paused, the main thread can continue to execute other tasks. The await function is a core concept in coroutine. What makes the whole thing so magical.

load()The lifecycle observer added to the function will be called on our activity.onDestroy()And then cancel the first coroutine. This will also cause the second coroutine to be canceled and blocked.block()Called.

Kotlin Coroutine DSL

Now we have two extended functions and a class that will handle the cancellation of coroutine. Let's take a look at how to use them:

load { loadBitmapFromMediaStore(imageId, imagesBaseUri)} then { imageView.setImageBitmap(it)}

In the above Code, we pass the lambda Method to the load function, which calls the loadBitmapFromMediaStore method. This function must be executed on the background thread until the method returns a Bitmap. the return value of the load method isDeferred<Bitmap>.

As an extension function,then()Methods are declared using infix, although the load method returnsDeferred<Bitmap>But it will be transmitted to a bitmap return value of the then method, so we can call it directly in the then method.imageView.setImageBitmap(it) .

The above code can be used for any asynchronous call that needs to occur on the background thread, and the return value should be returned to the place of the main thread, as shown in the above example. Unlike RxJava, it can write multiple calls, but it is easier to read and may cover many of the most common cases. Now you can do this safely without worrying about causing context leakage or processing threads in each call;

load { restApi.fetchData(query) } then { adapter.display(it) }

The then () and load () methods are just the tip of the iceberg of this new library, but I do want to see similar things in the future Kotlin-based Android library, once the coroutine version reaches the stable version. Before that, you can use or modify the above Code or view Anko Coroutines. I also released a more complete version on GitHub. (Https://github.com/ErikHellman/KotlinAsyncWithCoroutines (local download )).

Summary

The above is all the content of this article. I hope the content of this article has some reference and learning value for everyone's learning or work. If you have any questions, please leave a message to us, thank you for your support.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.