Work manager

WorkManager allows to schedule deferrable, asynchronous tasks that are expected to run even if the app exits or the device restarts.

You can create one-time work with the OneTimeWorkRequest class or periodical work with the PeriodicWorkRequest class. In both cases you can specify initial delay.

Constraints ensure that work is deferred until optimal conditions are met. For example, you want to execute work when WI-FI present.

Work can be tagged and named as well, allowing you to schedule unique, replaceable work and monitor or cancel groups of work together.

The WorkManager API is recommended replacement for all previous Android background scheduling APIs, including FirebaseJobDispatcher, GcmNetworkManager, and Job Scheduler.

Using of WorkManager
WorkManager.getInstance(context)
    .beginWith(listOf(workA,workB))
    .then(workC)
    .enqueue()

dependency

dependencies {
    val work_version = "2.5.0"

    // (Java only)
    implementation("androidx.work:work-runtime:$work_version")

    // Kotlin + coroutines
    implementation("androidx.work:work-runtime-ktx:$work_version")

    // optional - RxJava2 support
    implementation("androidx.work:work-rxjava2:$work_version")

    // optional - GCMNetworkManager support
    implementation("androidx.work:work-gcm:$work_version")

    // optional - Test helpers
    androidTestImplementation("androidx.work:work-testing:$work_version")

    // optional - Multiprocess support
    implementation "androidx.work:work-multiprocess:$work_version"
}
 
dependencies {
    def work_version = "2.5.0"

    // (Java only)
    implementation "androidx.work:work-runtime:$work_version"

    // Kotlin + coroutines
    implementation "androidx.work:work-runtime-ktx:$work_version"

    // optional - RxJava2 support
    implementation "androidx.work:work-rxjava2:$work_version"

    // optional - GCMNetworkManager support
    implementation "androidx.work:work-gcm:$work_version"

    // optional - Test helpers
    androidTestImplementation "androidx.work:work-testing:$work_version"

    // optional - Multiprocess support
    implementation "androidx.work:work-multiprocess:$work_version"
}

define work

Work is defined using the Worker class. The doWork() method runs asynchronously on a background thread provided by WorkManager.

To create some work for WorkManager to run, extend the Worker class and override the doWork() method.

class UploadWorker(appContext: Context, workerParams: WorkerParameters):
       Worker(appContext, workerParams) {
   override fun doWork(): Result {

       // do something
       uploadImages()

       // Indicate whether the work finished successfully with the Result
       return Result.success()
   }
}

To use Kotlin coroutines, you should extend CoroutineWorker class and override a suspending version of doWork(). Don't forget to add androidx.work:work-runtime-ktx dependency.

Coroutine worker

By default Dispatchers.Default is used. You can customize this by providing your own CoroutineContext as in example below.

Coroutine worker with custom dispatcher

work request

The WorkRequest defines work, that you can pass to WorkManager.

val myWorkRequest = OneTimeWorkRequest.from(MyWork::class.java)

val uploadWorkRequest: WorkRequest =
   OneTimeWorkRequestBuilder<MyWork>()
       // Additional configuration
       .build()
More requests examples

work constraints

When multiple constraints are specified, your work will run only when all the constraints are met.

In the event that a constraint becomes unmet while your work is running, WorkManager will stop your worker. The work will then be retried when all the constraints are met.

val constraints = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.UNMETERED) // WI-FI
    .setRequiresCharging(false)
    .setRequiresDeviceIdle(true)
    .setRequiresBatteryNotLow(true)
    .build()

val myWorkRequest: WorkRequest =
   OneTimeWorkRequestBuilder<MyWork>()
       .setConstraints(constraints)
       .build()

chaining work

WorkManager allows you to create and enqueue a chain of work that specifies multiple dependent tasks and defines what order they should run in. This functionality is particularly useful when you need to run several tasks in a particular order.

WorkManager.getInstance(myContext)
   // Candidates to run in parallel
   .beginWith(listOf(plantName1, plantName2, plantName3))
   // Dependent work (only runs after all previous work in chain)
   .then(cache)
   .then(upload)
   // Call enqueue to kick things off
   .enqueue()

work progress

ListenableWorker now supports the setProgressAsync() API, which allows it to persist intermediate progress.

Simple ProgressWorker

To observe progress you can use the getWorkInfoById() or getWorkInfoByIdLiveData() methods, and get a reference to WorkInfo.

Observe progress example