Une fois que vous avez défini votre Worker
et votre WorkRequest
, la dernière étape consiste à placer vos travaux en file d'attente. Le moyen le plus simple de placer un travail en file d'attente est d'appeler la méthode WorkManager enqueue()
en transmettant la valeur WorkRequest
que vous souhaitez exécuter.
Kotlin
val myWork: WorkRequest = // ... OneTime or PeriodicWork WorkManager.getInstance(requireContext()).enqueue(myWork)
Java
WorkRequest myWork = // ... OneTime or PeriodicWork WorkManager.getInstance(requireContext()).enqueue(myWork);
Faites attention à ne pas créer de doublons lorsque vous mettez des travaux en file d'attente. Par exemple, une application peut essayer d'importer ses journaux dans un service de backend toutes les 24 heures. Si vous ne faites pas attention, vous pourriez finissent par placer la même tâche plusieurs fois en file d'attente, alors qu'elle n'a besoin qu'une seule fois. Pour atteindre cet objectif, vous pouvez programmer cette tâche comme un travail unique.
Travail unique
Le travail unique est un concept puissant qui garantit qu'une seule instance de travail dispose d'un nom spécifique à la fois. Contrairement aux identifiants, les noms uniques sont lisibles et spécifiés par le développeur au lieu d'être générés automatiquement par WorkManager. Contrairement aux balises, les noms uniques ne sont associés qu'à une seule instance de travail.
Un travail unique peut être appliqué à un travail ponctuel ou périodique. Vous pouvez créer une séquence de travail unique en appelant l'une de ces méthodes, selon que vous planifiez un travail ponctuel ou périodique.
WorkManager.enqueueUniqueWork()
pour un travail ponctuelWorkManager.enqueueUniquePeriodicWork()
pour un travail périodique
Ces deux méthodes acceptent trois arguments :
- uniqueWorkName –
String
permettant d'identifier de manière unique la demande de travail. - existingWorkPolicy –
enum
indiquant à WorkManager ce qu'il faut faire en cas de chaîne de travail inachevée avec ce nom unique. Pour en savoir plus, consultez le Règlement concernant la résolution des conflits. - work –
WorkRequest
à planifier.
Grâce au travail unique, nous pouvons résoudre le problème de planification en double mentionné plus haut.
Kotlin
val sendLogsWorkRequest = PeriodicWorkRequestBuilder<SendLogsWorker>(24, TimeUnit.HOURS) .setConstraints(Constraints.Builder() .setRequiresCharging(true) .build() ) .build() WorkManager.getInstance(this).enqueueUniquePeriodicWork( "sendLogs", ExistingPeriodicWorkPolicy.KEEP, sendLogsWorkRequest )
Java
PeriodicWorkRequest sendLogsWorkRequest = new PeriodicWorkRequest.Builder(SendLogsWorker.class, 24, TimeUnit.HOURS) .setConstraints(new Constraints.Builder() .setRequiresCharging(true) .build() ) .build(); WorkManager.getInstance(this).enqueueUniquePeriodicWork( "sendLogs", ExistingPeriodicWorkPolicy.KEEP, sendLogsWorkRequest);
Si le code s'exécute alors qu'une tâche sendLogs figure déjà dans la file d'attente, la tâche existante est conservée et aucune nouvelle tâche n'est ajoutée.
Les séquences de travail uniques peuvent également être utiles si vous avez besoin de créer une longue chaîne de tâches progressivement. Par exemple, une application de retouche photo peut permettre aux utilisateurs d'annuler une longue chaîne d'actions. Les opérations d'annulation individuelles peuvent prendre un certain temps, mais elles doivent être effectuées dans le bon ordre. Dans ce cas, l'application peut créer une chaîne "annuler" et ajouter chaque opération d'annulation à la chaîne si nécessaire. Pour en savoir plus, consultez Enchaînement de travaux.
Règlement concernant la résolution des conflits
Lorsque vous planifiez un travail unique, vous devez indiquer à WorkManager l'action à effectuer en cas de conflit. Pour ce faire, transmettez une énumération lors de la mise en file d'attente de la tâche.
Pour un travail ponctuel, vous devez fournir un objet ExistingWorkPolicy
, qui accepte quatre options de gestion du conflit.
REPLACE
(remplacer) une tâche existante par une nouvelle tâche. Cette option annule la tâche existante.KEEP
(conserver) une tâche existante et ignorer les nouvelles tâches.APPEND
(ajouter) les nouvelles tâches à la fin des tâches existantes. Avec ce règlement, vos nouvelles tâches seront associées aux tâches existantes, une fois celles-ci terminées.
Les tâches existantes deviennent un prérequis pour les nouvelles tâches. Si les tâches existantes sont CANCELLED
ou FAILED
, les nouvelles tâches seront également CANCELLED
ou FAILED
.
Si vous souhaitez exécuter les nouvelles tâches, quel que soit l'état des tâches existantes, utilisez plutôt APPEND_OR_REPLACE
.
APPEND_OR_REPLACE
fonctionne de la même manière queAPPEND
, sauf qu'il ne dépend pas de l'état des tâches prérequis. Si les tâches existantes sontCANCELLED
ouFAILED
, les nouvelles tâches s'exécutent toujours.
Pour les tâches régulières, vous devez spécifier un objet ExistingPeriodicWorkPolicy
qui accepte deux options : REPLACE
et KEEP
. Ces options fonctionnent de la même manière que les équivalents ExistingWorkPolicy.
Observer votre travail
À tout moment après avoir mis une tâche en file d'attente, vous pouvez vérifier son état en interrogeant WorkManager par son name
, son id
ou une tag
associée.
Kotlin
// by id workManager.getWorkInfoById(syncWorker.id) // ListenableFuture<WorkInfo> // by name workManager.getWorkInfosForUniqueWork("sync") // ListenableFuture<List<WorkInfo>> // by tag workManager.getWorkInfosByTag("syncTag") // ListenableFuture<List<WorkInfo>>
Java
// by id workManager.getWorkInfoById(syncWorker.id); // ListenableFuture<WorkInfo> // by name workManager.getWorkInfosForUniqueWork("sync"); // ListenableFuture<List<WorkInfo>> // by tag workManager.getWorkInfosByTag("syncTag"); // ListenableFuture<List<WorkInfo>>
La requête renvoie un ListenableFuture
d'un objet WorkInfo
, qui inclut l'id
de la tâche, ses balises, son State
actuel et des données de sortie définies via Result.success(outputData)
.
Une variante LiveData
de chacune des méthodes vous permet d'observer les modifications apportées à WorkInfo
en enregistrant un écouteur. Par exemple, si vous souhaitez afficher un message lorsque l'utilisateur termine une tâche, vous pouvez le configurer comme suit :
Kotlin
workManager.getWorkInfoByIdLiveData(syncWorker.id) .observe(viewLifecycleOwner) { workInfo -> if(workInfo?.state == WorkInfo.State.SUCCEEDED) { Snackbar.make(requireView(), R.string.work_completed, Snackbar.LENGTH_SHORT) .show() } }
Java
workManager.getWorkInfoByIdLiveData(syncWorker.id) .observe(getViewLifecycleOwner(), workInfo -> { if (workInfo.getState() != null && workInfo.getState() == WorkInfo.State.SUCCEEDED) { Snackbar.make(requireView(), R.string.work_completed, Snackbar.LENGTH_SHORT) .show(); } });
Requêtes de travail complexes
WorkManager 2.4.0 et versions ultérieures acceptent les requêtes complexes pour les tâches mises en file d'attente à l'aide d'objets WorkQuery
. WorkQuery permet d'effectuer des requêtes concernant des travaux en associant une ou plusieurs balises, l'état et le nom de travail unique.
L'exemple suivant montre comment trouver tous les travaux avec la balise "syncTag", qui sont dans l'état FAILED
ou CANCELLED
et dont le nom de travail unique est "preProcess" ou "sync".
Kotlin
val workQuery = WorkQuery.Builder .fromTags(listOf("syncTag")) .addStates(listOf(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED)) .addUniqueWorkNames(listOf("preProcess", "sync") ) .build() val workInfos: ListenableFuture<List<WorkInfo>> = workManager.getWorkInfos(workQuery)
Java
WorkQuery workQuery = WorkQuery.Builder .fromTags(Arrays.asList("syncTag")) .addStates(Arrays.asList(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED)) .addUniqueWorkNames(Arrays.asList("preProcess", "sync") ) .build(); ListenableFuture<List<WorkInfo>> workInfos = workManager.getWorkInfos(workQuery);
Chaque composant (balise, état ou nom) d'une WorkQuery
est mis en rapport via AND
avec les autres. Chaque valeur d'un composant est mise en rapport via OR
. Exemple : (name1 OR name2
OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...)
.
WorkQuery
fonctionne également avec l'équivalent LiveData getWorkInfosLiveData()
.
Annuler et arrêter un travail
Si vous n'avez plus besoin d'exécuter un travail précédemment placé en file d'attente, vous pouvez demander son annulation. Une tâche peut être annulée via son name
, son id
ou une tag
associée.
Kotlin
// by id workManager.cancelWorkById(syncWorker.id) // by name workManager.cancelUniqueWork("sync") // by tag workManager.cancelAllWorkByTag("syncTag")
Java
// by id workManager.cancelWorkById(syncWorker.id); // by name workManager.cancelUniqueWork("sync"); // by tag workManager.cancelAllWorkByTag("syncTag");
En arrière-plan, WorkManager vérifie le State
de la tâche. Si l'opération est déjà terminée, rien ne se passe. Sinon, l'état de la tâche est définie sur CANCELLED
, et la tâche ne s'exécute plus par la suite. Toutes les tâches WorkRequest
dépendantes de ce travail seront également CANCELLED
.
Actuellement, le travail RUNNING
reçoit un appel à ListenableWorker.onStopped()
.
Ignorez cette méthode pour gérer tout nettoyage potentiel. Pour en savoir plus, consultez Arrêter un nœud de calcul en cours d'exécution.
Arrêter un nœud de calcul en cours d'exécution
Votre Worker
peut être arrêté par WorkManager pour différentes raisons :
- Vous avez explicitement demandé son annulation (en appelant
WorkManager.cancelWorkById(UUID)
, par exemple). - Dans le cas d'un travail unique, vous avez explicitement mis en file d'attente un nouvel élément
WorkRequest
avec un élémentExistingWorkPolicy
défini surREPLACE
. L'ancienneWorkRequest
est immédiatement considérée comme étant annulée. - Les contraintes de votre travail ne sont plus respectées.
- Le système a demandé à votre application d'arrêter votre travail pour une raison inconnue. Cela peut se produire si vous dépassez le délai d'exécution de 10 minutes. Le travail est programmé pour être relancé ultérieurement.
Dans ces conditions, votre nœud de calcul est arrêté.
Vous devez coopérer pour abandonner tout travail en cours et libérer toutes les ressources que votre nœud de calcul détient. Par exemple, vous devez fermer les handles ouvertes des bases de données et des fichiers à ce stade. Deux mécanismes sont à votre disposition pour comprendre quand votre nœud de calcul s'arrête.
Rappel onStopped()
WorkManager appelle ListenableWorker.onStopped()
dès que votre nœud de calcul a été arrêté. Ignorez cette méthode pour fermer les ressources que vous pourriez conserver.
Propriété isStopped()
Vous pouvez appeler la méthode ListenableWorker.isStopped()
pour vérifier si votre nœud de calcul a déjà été arrêté. Si vous effectuez des opérations de longue durée ou répétitives dans votre nœud de calcul, vous devez souvent vérifier cette propriété et l'utiliser comme signal pour arrêter des tâches dès que possible.
Remarque : WorkManager ignore le Result
défini par un nœud de calcul ayant reçu le signal onStop, car il est déjà considéré comme étant arrêté.