For Kotlin users, WorkManager provides first-class support for coroutines. To get
started, include work-runtime-ktx
in your gradle file. Instead of extending Worker
, you should extend CoroutineWorker
, which has a suspending
version of doWork()
. For example, if you wanted to build a simple CoroutineWorker
to perform some network operations, you would do the following:
class CoroutineDownloadWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
val data = downloadSynchronously("https://www.google.com")
saveData(data)
return Result.success()
}
}
Note that CoroutineWorker.doWork()
is a suspending
function. Unlike Worker
, this code does not run on the Executor
specified
in your Configuration
. Instead, it
defaults to Dispatchers.Default
. You can customize this by providing your own CoroutineContext
. In the above example, you would probably want to do this work on Dispatchers.IO
, as follows:
class CoroutineDownloadWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
withContext(Dispatchers.IO) {
val data = downloadSynchronously("https://www.google.com")
saveData(data)
return Result.success()
}
}
}
CoroutineWorker
handles stoppages automatically by cancelling the coroutine
and propagating the cancellation signals. You don't need to do anything special
to handle work stoppages.
Running a CoroutineWorker in a different process
You can also bind a worker to a specific process by using
RemoteCoroutineWorker
,
an implementation of ListenableWorker
.
RemoteCoroutineWorker
binds to a specific process with two extra arguments
that you provide as part of the input data when building the work request:
ARGUMENT_CLASS_NAME
and ARGUMENT_PACKAGE_NAME
.
The following example demonstrates building a work request that is bound to a specific process:
Kotlin
val PACKAGE_NAME = "com.example.background.multiprocess" val serviceName = RemoteWorkerService::class.java.name val componentName = ComponentName(PACKAGE_NAME, serviceName) val data: Data = Data.Builder() .putString(ARGUMENT_PACKAGE_NAME, componentName.packageName) .putString(ARGUMENT_CLASS_NAME, componentName.className) .build() return OneTimeWorkRequest.Builder(ExampleRemoteCoroutineWorker::class.java) .setInputData(data) .build()
Java
String PACKAGE_NAME = "com.example.background.multiprocess"; String serviceName = RemoteWorkerService.class.getName(); ComponentName componentName = new ComponentName(PACKAGE_NAME, serviceName); Data data = new Data.Builder() .putString(ARGUMENT_PACKAGE_NAME, componentName.getPackageName()) .putString(ARGUMENT_CLASS_NAME, componentName.getClassName()) .build(); return new OneTimeWorkRequest.Builder(ExampleRemoteCoroutineWorker.class) .setInputData(data) .build();
For each RemoteWorkerService
, you also need to add a service definition in
your AndroidManifest.xml
file:
<manifest ... > <service android:name="androidx.work.multiprocess.RemoteWorkerService" android:exported="false" android:process=":worker1" /> <service android:name=".RemoteWorkerService2" android:exported="false" android:process=":worker2" /> ... </manifest>