WorkManager provides a set of apis to make it easier to plan asynchronous tasks, even after the application is shut down or the device is restarted, to ensure that immediate or delayed tasks are processed properly. For Kotlin developers, WorkManager provides the best support for coroutines. In this article, I will show you the basic operations related to coroutines in WorkManager through the WorkManager Codelab practice. So let’s get started!

The WorkManager basis

WorkManager is recommended when you need to keep a task running even when the user switches to another interface, or the application switches to the background, or the device restarts. Similar application scenarios include:

  • Upload logs or report data
  • Save images while using filters
  • Periodically synchronize local data over the network

If your immediate task can end when the user leaves a scope, such as switching to another interface, we recommend that you use the Kotlin coroutine directly.

In this WorkManager Codelab tutorial, we will blur the images and store the processed data on disk. So let’s see what we need to do in this process.

Add work-Run-time KTX dependencies:

/ / get the latest version number https://developer.android.google.cn/jetpack/androidx/releases/work def work_version = "2.5.0" implementation  "androidx.work:work-runtime-ktx:$work_version"Copy the code

Start by implementing our own Worker class. This is where we implement the code that really needs to execute the business in the background. You can extend the Worker class and override the doWork() method. Since this class is very important, we’ll cover it in more detail later. Here is the original implementation code.

/* Copyright 2020 Google LLC.spdx-license-Identifier: Apache-2.0 */

class BlurWorker(ctx: Context, params: WorkerParameters) : Worker(ctx, params) {

    override fun doWork(a): Result {
        val resourceUri = inputData.getString(KEY_IMAGE_URI)

        return try {
            if (resourceUri.isNullOrEmpty()) {
                Timber.e("Invalid input uri")
                throw IllegalArgumentException("Invalid input uri")}val outputData = blurAndWriteImageToFile(resourceUri)
            Result.success(outputData)
        } catch (throwable: Throwable) {
            Timber.e(throwable, "Error applying blur")
            Result.failure()
        }
    }
…
}
Copy the code

Next, create our work request, in this case, we hope that the whole operation runs only once, so we use OneTimeWorkRequest. Builder, will need to deal with the blurred images the Uri of the incoming as arguments.

Kotlin tip: To create input data, we can use the workDataOf function, which will create the data builder for us, populate the key-value pairs, and then create the data for us.

/* Copyright 2020 Google LLC.spdx-license-Identifier: Apache-2.0 */

val blurBuilder = OneTimeWorkRequestBuilder<BlurWorker>()
val data = workDataOf(KEY_IMAGE_URI to imageUri.toString())
blurBuilder.setInputData(data)
Copy the code

We use the WorkManager class to add the work done above to the schedule queue and run it. We can provide the tasks that need to be performed and the constraints on those tasks.

/* Copyright 2020 Google LLC.spdx-license-Identifier: Apache-2.0 */

val workManager = WorkManager.getInstance(application)
val continuation = workManager.beginUniqueWork(blurBuilder.build())
// Execute the task
continuation.enqueue()
Copy the code

Causes the Worker to start executing the task

When you use Worker, WorkManager automatically calls worker.dowork () in the background thread. The Result returned by doWork() tells The WorkManager whether the service succeeded or whether it needs to be retried if it failed.

Worker.dowork () is a synchronous call — your background operations need to be blocked and all tasks need to be completed at the end of the entire doWork() function. If you call an asynchronous API in doWork() and then return the result, you may have problems executing the callback function.

But what if I want to do something asynchronous?

Let’s make the above example a little more complicated, such as I want to store the URIs of all the files that are being obfuscated in the database.

So I created:

  • A simple BlurredImage entity
  • A DAO class for inserting and retrieving images
  • The database

Click here for the implementation code.

In Kotlin, we recommend CoroutineWorker if you need to perform asynchronous operations, such as storing data in a database or making network requests.

CoroutineWorker uses Kotlin coroutines to perform asynchronous tasks.

The doWork() method is a suspend method. This means that we can call the suspended DAO function here.

/* Copyright 2020 Google LLC.spdx-license-Identifier: Apache-2.0 */

class BlurWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx, params) {

    override suspend fun doWork(a): Result {
        val resourceUri = inputData.getString(KEY_IMAGE_URI)

        return try {
            if (resourceUri.isNullOrEmpty()) {
                Timber.e("Invalid input uri")
                throw IllegalArgumentException("Invalid input uri")}val outputData = blurAndWriteImageToFile(resourceUri)
            // Store the URI to the database
           val imageDao = ImagesDatabase.getDatabase(applicationContext).blurredImageDao()
            imageDao.insert(BlurredImage(resourceUri))

            Result.success(outputData)
        } catch (throwable: Throwable) {
            Timber.e(throwable, "Error applying blur")
            Result.failure()
        }
    }
...
}
Copy the code

DoWork () uses dispatchers.default by Default. You can replace it with the Dispatcher you need. In this case, we don’t need to do this because Room already does the data insertion in a separate Dispatcher. For more information, see the Room Kotlin API.

Start using CoroutineWorker to perform asynchronous tasks that can be completed even if the user closes the application.

If you want to learn more about WorkManager, keep an eye out for future articles. Until then, visit our Codelab and documentation:

  • The WorkManager document
  • Use the WorkManager Codelab |
  • Codelab | WorkManager advanced