Exécuter des threads dans CoroutineWorker

Pour les utilisateurs de Kotlin, WorkManager offre une prise en charge de premier ordre pour les coroutines. Pour commencer, incluez work-runtime-ktx dans votre fichier Gradle. Au lieu de Worker, vous devez étendre CoroutineWorker, qui possède une version de suspension de doWork(). Par exemple, si vous souhaitez créer un CoroutineWorker simple pour effectuer certaines opérations réseau, procédez comme suit :

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

Notez que CoroutineWorker.doWork() est une fonction de suspension. Contrairement à Worker, ce code ne s'exécute pas sur l'Executor spécifié dans votre Configuration. Au lieu de cela, il est défini par défaut sur Dispatchers.Default. Vous pouvez personnaliser cette fonction en fournissant votre propre CoroutineContext. Dans l'exemple ci-dessus, vous souhaiterez probablement effectuer cette tâche sur Dispatchers.IO, comme suit :

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 gère automatiquement les arrêts en annulant la coroutine et en propageant les signaux d'annulation. Aucune action spéciale n'est requise pour gérer les arrêts de tâches.

Exécuter un CoroutineWorker dans un processus différent

Vous pouvez également lier un nœud de calcul à un processus spécifique à l'aide de RemoteCoroutineWorker : une implémentation de ListenableWorker.

RemoteCoroutineWorker se lie à un processus spécifique avec deux arguments supplémentaires que vous fournissez dans les données d'entrée lors de la création de la requête de tâche : ARGUMENT_CLASS_NAME et ARGUMENT_PACKAGE_NAME.

L'exemple suivant illustre la création d'une requête de tâche liée à un processus spécifique :

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

Pour chaque RemoteWorkerService, vous devez également ajouter une définition de service dans votre fichier 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>

Exemples