Потоки в CoroutineWorker

Для пользователей Kotlin WorkManager обеспечивает первоклассную поддержку сопрограмм . Для начала включите work-runtime-ktx в свой файл gradle . Вместо расширения Worker вам следует расширить CoroutineWorker , который имеет приостанавливающую версию doWork() . Например, если вы хотите создать простой CoroutineWorker для выполнения некоторых сетевых операций, вы должны сделать следующее:

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()
    }
}

Обратите внимание, что CoroutineWorker.doWork() — это приостанавливающая функция. В отличие от Worker , этот код не запускается на Executor указанном в вашей Configuration . Вместо этого по умолчанию используется Dispatchers.Default . Вы можете настроить это, предоставив свой собственный CoroutineContext . В приведенном выше примере вы, вероятно, захотите проделать эту работу с Dispatchers.IO следующим образом:

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 автоматически обрабатывает остановки, отменяя сопрограмму и распространяя сигналы отмены. Вам не нужно делать ничего особенного, чтобы справиться с перерывами в работе .

Запуск CoroutineWorker в другом процессе

Вы также можете привязать работника к определенному процессу с помощью RemoteCoroutineWorker , реализации ListenableWorker .

RemoteCoroutineWorker привязывается к конкретному процессу с помощью двух дополнительных аргументов, которые вы предоставляете как часть входных данных при создании рабочего запроса: ARGUMENT_CLASS_NAME и ARGUMENT_PACKAGE_NAME .

В следующем примере показано создание рабочего запроса, привязанного к определенному процессу:

Котлин

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()

Ява

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();

Для каждого RemoteWorkerService вам также необходимо добавить определение службы в файл AndroidManifest.xml :

<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>