Mettre à jour un travail déjà mis en file d'attente

WorkManager vous permet de mettre à jour une WorkRequest après l'avoir déjà placée en file d'attente. Cette opération est souvent nécessaire dans les applications plus volumineuses qui changent fréquemment les contraintes ou qui doivent mettre à jour leurs nœuds de calcul à la volée. Depuis la version 2.8.0 de WorkManager, l'API updateWork() permet d'effectuer cette opération.

La méthode updateWork() vous permet de modifier certains aspects d'une WorkRequest à la volée, sans avoir à passer par le processus d'annulation manuelle et de mise en file d'attente d'une nouvelle mise en file d'attente. Cela simplifie considérablement le processus de développement.

Éviter d'annuler des tâches

En règle générale, vous devez éviter d'annuler une WorkRequest existante et d'en ajouter une nouvelle. Cela peut entraîner la répétition de certaines tâches par l'application et vous obliger à écrire une quantité importante de code supplémentaire.

Voici quelques exemples dans lesquels l'annulation d'une requête de travail peut entraîner des difficultés:

  • Requête backend:si vous annulez un Worker pendant qu'il calcule une charge utile à envoyer au serveur, le nouveau Worker doit recommencer et recalculer la charge utile potentiellement coûteuse.
  • Planification:si vous annulez une PeriodicWorkRequest et que vous souhaitez que le nouveau PeriodicWorkRequest s'exécute selon la même planification, vous devez calculer un décalage temporel pour vous assurer que le nouveau délai d'exécution correspond à la requête de travail précédente.

L'API updateWork() vous permet de mettre à jour les contraintes et les autres paramètres d'une requête de travail sans avoir à annuler ni mettre une nouvelle requête en file d'attente.

Quand annuler la tâche

Dans certains cas, vous devez annuler directement une WorkRequest plutôt que d'appeler updateWork(). Voici ce que vous devez faire lorsque vous souhaitez modifier la nature fondamentale du travail que vous avez mis en file d'attente.

Quand mettre à jour une tâche

Imaginez une application photo qui effectue une sauvegarde quotidienne des photos de l'utilisateur. Il a placé un PeriodicWorkRequest en file d'attente pour effectuer cette opération. Le WorkRequest présente des contraintes qui nécessitent que l'appareil soit en charge et connecté au Wi-Fi.

Toutefois, l'utilisateur ne recharge son appareil que 20 minutes par jour à l'aide d'un chargeur rapide. Dans ce cas, l'application peut vouloir mettre à jour WorkRequest pour assouplir la contrainte de recharge, afin de pouvoir importer les photos même si l'appareil n'est pas complètement chargé.

Dans ce cas, vous pouvez utiliser la méthode updateWork() pour mettre à jour les contraintes de la requête de tâche.

Mettre à jour une tâche

La méthode updateWork() permet de mettre à jour facilement une WorkRequest existante, sans avoir à en annuler une nouvelle et à la mettre en file d'attente.

Pour utiliser la tâche de mise à jour mise en file d'attente, procédez comme suit:

  1. Obtenir l'ID existant du travail mis en file d'attente: obtenez l'ID de la requête de travail que vous souhaitez mettre à jour. Vous pouvez récupérer cet ID à l'aide de n'importe quelle API getWorkInfo ou en conservant manuellement l'ID à partir de la requête de travail initiale pour une récupération ultérieure avec la propriété publique WorkRequest.id, avant de l'ajouter à la file d'attente.
  2. Create new WorkRequest (Créer une requête de travail) : créez un WorkRequest et utilisez WorkRequest.Builder.setID() pour définir son ID afin qu'il corresponde à celui du WorkRequest existant.
  3. Définir des contraintes: utilisez WorkRequest.Builder.setConstraints() pour transmettre les nouvelles contraintes de WorkManager.
  4. Call updateWork: transmettez la nouvelle WorkRequest à updateWork().

Exemple de tâche de mise à jour

Voici un exemple d'extrait de code en Kotlin qui montre comment utiliser la méthode updateWork() pour modifier les contraintes de batterie d'un WorkRequest utilisé pour importer des photos:

suspend fun updatePhotoUploadWork() {
    // Get instance of WorkManager.
    val workManager = WorkManager.getInstance(context)

    // Retrieve the work request ID. In this example, the work being updated is unique
    // work so we can retrieve the ID using the unique work name.
    val photoUploadWorkInfoList = workManager.getWorkInfosForUniqueWork(
        PHOTO_UPLOAD_WORK_NAME
    ).await()

    val existingWorkRequestId = photoUploadWorkInfoList.firstOrNull()?.id ?: return

    // Update the constraints of the WorkRequest to not require a charging device.
    val newConstraints = Constraints.Builder()
        // Add other constraints as required here.
        .setRequiresCharging(false)
        .build()

    // Create new WorkRequest from existing Worker, new constraints, and the id of the old WorkRequest.
    val updatedWorkRequest: WorkRequest =
        OneTimeWorkRequestBuilder<MyWorker>()
            .setConstraints(newConstraints)
            .setId(existingWorkRequestId)
            .build()

    // Pass the new WorkRequest to updateWork().
    workManager.updateWork(updatedWorkRequest)
}

Gérer le résultat

updateWork() renvoie un ListenableFuture<UpdateResult>. L'élément UpdateResult donné peut avoir l'une des valeurs indiquant si WorkManager a pu ou non appliquer vos modifications. Elle indique également quand la modification a été appliquée.

Pour en savoir plus, consultez la documentation de référence sur updateWork() et UpdateResult.

Suivre le travail des générations

Chaque fois que vous mettez à jour un WorkRequest, sa génération s'incrémente d'une unité. Cela vous permet de suivre exactement quel WorkRequest est actuellement mis en file d'attente. Les générations vous offrent plus de contrôle lors de l'observation, du traçage et du test des requêtes de travail.

Pour obtenir la génération d'un WorkRequest, procédez comme suit:

  1. WorkInfo: appelez WorkManager.getWorkInfoById() pour récupérer une instance de WorkInfo correspondant à votre WorkRequest.
  2. getGeneration: appelez getGeneration() sur l'instance de WorkInfo. Le Int renvoyé correspond à la génération de WorkRequest.
    • Notez qu'il n'y a pas de champ ou de propriété de génération, mais uniquement la méthode WorkInfo.getGeneration().

Exemple de génération de canaux

Voici un exemple d'implémentation du workflow décrit ci-dessus pour récupérer la génération d'un WorkRequest.

// Get instance of WorkManager.
val workManager = WorkManager.getInstance(context)

// Retrieve WorkInfo instance.
val workInfo = workManager.getWorkInfoById(oldWorkRequestId)

// Call getGeneration to retrieve the generation.
val generation = workInfo.getGeneration()

Règles pour la mise à jour d'un devoir

Auparavant, la solution recommandée pour mettre à jour les tâches périodiques consistait à mettre en file d'attente un PeriodicWorkRequest avec la stratégie ExistingPeriodicWorkPolicy.REPLACE. S'il existe un PeriodicWorkRequest en attente avec le même id unique, la nouvelle requête de travail l'annule et la supprime. Cette règle est désormais obsolète au profit du workflow utilisant la ExistingPeriodicWorkPolicy.UPDATE.

Par exemple, lorsque vous utilisez enqueueUniquePeriodicWork avec un PeriodicWorkRequest, vous pouvez initialiser le nouveau PeriodicWorkRequest avec la règle ExistingPeriodicWorkPolicy.UPDATE. Si un objet PeriodicWorkRequest en attente porte le même nom unique, WorkManager le met à jour avec la nouvelle spécification. Conformément à ce workflow, il n'est pas nécessaire d'utiliser updateWork().