Cet atelier de programmation fait partie du cours Principes de base d'Android en Kotlin. Vous tirerez pleinement parti de ce cours en suivant les ateliers de programmation dans l'ordre. Tous les ateliers de programmation du cours sont listés sur la page de destination des ateliers de programmation Principes de base d'Android en Kotlin.
Introduction
La plupart des applications réelles doivent effectuer des tâches de longue durée en arrière-plan. Par exemple, une application peut importer des fichiers sur un serveur, synchroniser des données à partir d'un serveur et les enregistrer dans une base de données Room, envoyer des journaux à un serveur ou exécuter des opérations coûteuses sur des données. Ces opérations doivent être effectuées en arrière-plan, en dehors du thread UI (thread principal). Les tâches en arrière-plan consomment les ressources limitées d'un appareil, comme la RAM et la batterie. Si elle n'est pas gérée correctement, cela peut nuire à l'expérience utilisateur.
Dans cet atelier de programmation, vous allez apprendre à utiliser WorkManager pour planifier une tâche en arrière-plan de manière efficace et optimisée. Pour en savoir plus sur les autres solutions disponibles pour le traitement en arrière-plan dans Android, consultez le Guide relatif au traitement en arrière-plan.
Ce que vous devez déjà savoir
- Utiliser les composants d'architecture Android ViewModel,LiveDataetRoom.
- Comment effectuer des transformations sur une classe LiveData.
- Créer et lancer une coroutine
- Utiliser des adaptateurs de liaison dans la liaison de données
- Comment charger des données mises en cache à l'aide d'un modèle de dépôt
Points abordés
- Comment créer un Worker, qui représente une unité de travail.
- Découvrez comment créer une WorkRequestpour demander l'exécution d'une tâche.
- Ajouter des contraintes à WorkRequestpour définir comment et quand un nœud de calcul doit s'exécuter.
- Utiliser WorkManagerpour planifier des tâches en arrière-plan.
Objectifs de l'atelier
- Créez un worker pour exécuter une tâche en arrière-plan afin de précharger la playlist de vidéos DevBytes à partir du réseau.
- Planifiez l'exécution du worker à intervalles réguliers.
- Ajoutez des contraintes à WorkRequest.
- Planifiez un WorkRequestpériodique qui s'exécute une fois par jour.
Dans cet atelier de programmation, vous allez travailler sur l'application DevBytes que vous avez développée dans un atelier précédent. (Si vous n'avez pas cette application, vous pouvez télécharger le code de démarrage pour cette leçon.)
L'application DevBytes affiche une liste de vidéos DevBytes, qui sont de courts tutoriels réalisés par l'équipe Google chargée des relations avec les développeurs Android. Les vidéos présentent les fonctionnalités pour les développeurs et les bonnes pratiques de développement Android.
Vous améliorez l'expérience utilisateur dans l'application en préchargeant les vidéos une fois par jour. Cela garantit que l'utilisateur obtient du contenu récent dès qu'il ouvre l'application.

Dans cette tâche, vous allez télécharger et inspecter le code de démarrage.
Étape 1 : Téléchargez et exécutez l'application de démarrage
Vous pouvez continuer à travailler sur l'application DevBytes que vous avez créée dans l'atelier de programmation précédent (si vous l'avez). Vous pouvez également télécharger l'application de démarrage.
Dans cette tâche, vous allez télécharger et exécuter l'application de démarrage, puis examiner le code de démarrage.
- Si vous ne disposez pas encore de l'application DevBytes, téléchargez le code de démarrage DevBytes pour cet atelier de programmation à partir du projet DevBytesRepository sur GitHub.
- Décompressez le code et ouvrez le projet dans Android Studio.
- Connectez votre appareil de test ou votre émulateur à Internet, si ce n'est pas déjà fait. Créez et exécutez l'application. Elle récupère la liste des vidéos DevByte sur le réseau et les affiche.
- Dans l'application, appuyez sur une vidéo pour l'ouvrir dans l'application YouTube.
Étape 2 : Explorer le code
L'application de démarrage contient beaucoup de code qui a été présenté dans l'atelier de programmation précédent. Le code de démarrage de cet atelier de programmation comporte des modules de mise en réseau, d'interface utilisateur, de cache hors connexion et de dépôt. Vous pouvez vous concentrer sur la planification de la tâche en arrière-plan à l'aide de WorkManager. 
- Dans Android Studio, développez tous les packages.
- Explorez le package database. Le package contient les entités de base de données et la base de données locale, qui est implémentée à l'aide deRoom.
- Explorez le package repository. Le package contient la classeVideosRepositoryqui sépare la couche de données du reste de l'application.
- Explorez le reste du code de démarrage par vous-même, avec l'aide de l'atelier de programmation précédent.
WorkManager fait partie des composants d'architecture Android et d'Android Jetpack. WorkManager est destiné aux tâches en arrière-plan qui peuvent être différées et dont l'exécution doit être garantie :
- Différable signifie que le travail n'a pas besoin d'être exécuté immédiatement. Par exemple, l'envoi de données analytiques au serveur ou la synchronisation de la base de données en arrière-plan sont des tâches qui peuvent être différées.
- L'exécution garantie signifie que la tâche s'exécutera même si l'application se ferme ou si l'appareil redémarre.

WorkManager exécute des tâches en arrière-plan, gère les problèmes de compatibilité et applique les bonnes pratiques pour la batterie et l'état du système. WorkManager est rétrocompatible jusqu'au niveau d'API 14. WorkManager choisit la méthode appropriée pour planifier une tâche en arrière-plan, en fonction du niveau d'API de l'appareil. Il peut utiliser JobScheduler (sur l'API 23 et versions ultérieures) ou une combinaison de AlarmManager et BroadcastReceiver.
WorkManager vous permet également de définir des critères pour l'exécution de la tâche en arrière-plan. Par exemple, vous pouvez souhaiter que la tâche ne s'exécute que lorsque l'état de la batterie, l'état du réseau ou l'état de charge répondent à certains critères. Vous apprendrez à définir des contraintes plus loin dans cet atelier de programmation.
Dans cet atelier de programmation, vous allez planifier une tâche pour précharger la playlist de vidéos DevBytes à partir du réseau une fois par jour. Pour planifier cette tâche, vous utilisez la bibliothèque WorkManager.
- Ouvrez le fichier build.gradle (Module:app)et ajoutez la dépendanceWorkManagerau projet.
 Si vous utilisez la dernière version de la bibliothèque, l'application de solution devrait se compiler comme prévu. Si ce n'est pas le cas, essayez de résoudre le problème ou revenez à la version de la bibliothèque indiquée ci-dessous.
// WorkManager dependency
def work_version = "1.0.1"
implementation "android.arch.work:work-runtime-ktx:$work_version"- Synchronisez votre projet et assurez-vous qu'il ne comporte aucune erreur de compilation.
Avant d'ajouter du code au projet, familiarisez-vous avec les classes suivantes de la bibliothèque WorkManager :
- Worker
 Cette classe vous permet de définir le travail (la tâche) à exécuter en arrière-plan. Vous allez étendre cette classe et remplacer la méthode- doWork(). La méthode- doWork()vous permet d'insérer le code à exécuter en arrière-plan, par exemple pour synchroniser des données avec le serveur ou traiter des images. Dans cette tâche, vous allez implémenter- Worker.
- WorkRequest
 : cette classe représente une requête d'exécution du nœud de calcul en arrière-plan. Utilisez- WorkRequestpour configurer comment et quand exécuter la tâche de nœud de calcul, à l'aide de- Constraints, par exemple lorsque l'appareil est branché ou connecté au Wi-Fi. Vous implémenterez- WorkRequestdans une tâche ultérieure.
- WorkManager
 Cette classe planifie et exécute votre- WorkRequest.- WorkManagerplanifie les demandes de travail de manière à répartir la charge pesant sur les ressources système, tout en respectant les contraintes que vous spécifiez. Vous implémenterez- WorkManagerdans une tâche ultérieure.
Étape 1 : Créez un employé
Dans cette tâche, vous allez ajouter un Worker pour précharger la playlist de vidéos DevBytes en arrière-plan.
- Dans le package devbyteviewer, créez un package nomméwork.
- Dans le package work, créez une classe Kotlin appeléeRefreshDataWorker.
- Étendez la classe RefreshDataWorkerà partir deCoroutineWorker. TransmettezcontextetWorkerParametersen tant que paramètres de constructeur.
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {
}- Pour résoudre l'erreur de classe abstraite, remplacez la méthode doWork()dans la classeRefreshDataWorker.
override suspend fun doWork(): Result {
  return Result.success()
}Une fonction de suspension est une fonction qui peut être mise en pause et reprise ultérieurement. Une fonction de suspension peut exécuter une opération de longue durée et attendre qu'elle se termine sans bloquer le thread principal.
Étape 2 : Implémenter doWork()
La méthode doWork() à l'intérieur de la classe Worker est appelée sur un thread d'arrière-plan. La méthode effectue le travail de manière synchrone et doit renvoyer un objet ListenableWorker.Result. Le système Android accorde un délai maximal de 10 minutes à un Worker pour terminer son exécution et renvoyer un objet ListenableWorker.Result. Passé ce délai, le système arrête de force le Worker.
Pour créer un objet ListenableWorker.Result, appelez l'une des méthodes statiques suivantes pour indiquer l'état d'achèvement du travail en arrière-plan :
- Result.success(): le travail a été effectué avec succès.
- Result.failure(): le travail s'est terminé par un échec permanent.
- Result.retry(): le travail a rencontré un échec temporaire et doit être relancé.
Dans cette tâche, vous allez implémenter la méthode doWork() pour récupérer la playlist de vidéos DevBytes sur le réseau. Vous pouvez réutiliser les méthodes existantes dans la classe VideosRepository pour récupérer les données du réseau.
- Dans la classe RefreshDataWorker, à l'intérieur dedoWork(), créez et instanciez un objetVideosDatabaseet un objetVideosRepository.
override suspend fun doWork(): Result {
   val database = getDatabase(applicationContext)
   val repository = VideosRepository(database)
   return Result.success()
}- Dans la classe RefreshDataWorker, dansdoWork(), au-dessus de l'instructionreturn, appelez la méthoderefreshVideos()dans un bloctry. Ajoutez un journal pour suivre l'exécution du worker.
try {
   repository.refreshVideos( )
   Timber.d("Work request for sync is run")
   } catch (e: HttpException) {
   return Result.retry()
}Pour résoudre l'erreur "Référence non résolue", importez retrofit2.HttpException.
- Pour vous aider, voici la classe RefreshDataWorkercomplète :
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {
   override suspend fun doWork(): Result {
       val database = getDatabase(applicationContext)
       val repository = VideosRepository(database)
       try {
           repository.refreshVideos()
       } catch (e: HttpException) {
           return Result.retry()
       }
       return Result.success()
   }
}Un Worker définit une unité de travail, et WorkRequest définit comment et quand le travail doit être exécuté. Il existe deux implémentations concrètes de la classe WorkRequest : 
- La classe OneTimeWorkRequestest destinée aux tâches ponctuelles. (Une tâche ponctuelle n'a lieu qu'une seule fois.)
- La classe PeriodicWorkRequestest destinée aux travaux périodiques, c'est-à-dire aux travaux se répétant à intervalles réguliers.
Les tâches peuvent être ponctuelles ou périodiques. Choisissez le cours en conséquence. Pour en savoir plus sur la planification des tâches récurrentes, consultez la documentation sur les tâches récurrentes.
Dans cette tâche, vous allez définir et planifier un WorkRequest pour exécuter le worker que vous avez créé dans la tâche précédente. 
Étape 1 : Configurez les tâches récurrentes
Dans une application Android, la classe Application est la classe de base qui contient tous les autres composants, tels que les activités et les services. Lorsque le processus de votre application ou package est créé, la classe Application (ou toute sous-classe de Application) est instanciée avant toute autre classe.
Dans cet exemple d'application, la classe DevByteApplication est une sous-classe de la classe Application. La classe DevByteApplication est un bon endroit pour planifier WorkManager.
- Dans la classe DevByteApplication, créez une méthode appeléesetupRecurringWork()pour configurer le travail en arrière-plan récurrent.
/**
* Setup WorkManager background job to 'fetch' new network data daily.
*/
private fun setupRecurringWork() {
}- Dans la méthode setupRecurringWork(), créez et initialisez une requête de travail périodique à exécuter une fois par jour à l'aide de la méthodePeriodicWorkRequestBuilder(). Transmettez la classeRefreshDataWorkerque vous avez créée lors de la tâche précédente. Transmettez un intervalle de répétition de1avec une unité de temps deTimeUnit.DAYS.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
       .build()Pour résoudre l'erreur, importez java.util.concurrent.TimeUnit.
Étape 2 : Planifiez une WorkRequest avec WorkManager
Une fois votre WorkRequest défini, vous pouvez le planifier avec WorkManager à l'aide de la méthode enqueueUniquePeriodicWork(). Cette méthode vous permet d'ajouter un PeriodicWorkRequest portant un nom unique à la file d'attente, où un seul PeriodicWorkRequest d'un nom particulier peut être actif à la fois.
Par exemple, vous ne souhaitez peut-être qu'une seule opération de synchronisation active. Si une opération de synchronisation est en attente, vous pouvez choisir de la laisser s'exécuter ou de la remplacer par votre nouveau travail à l'aide d'une ExistingPeriodicWorkPolicy.
Pour en savoir plus sur la planification d'un WorkRequest, consultez la documentation WorkManager.
- Dans la classe RefreshDataWorker, au début de la classe, ajoutez un objet associé. Définissez un nom de worker pour identifier ce worker de manière unique.
companion object {
   const val WORK_NAME = "com.example.android.devbyteviewer.work.RefreshDataWorker"
}- Dans la classe DevByteApplication, à la fin de la méthodesetupRecurringWork(), planifiez le travail à l'aide de la méthodeenqueueUniquePeriodicWork(). Transmettez l'énumérationKEEPpour ExistingPeriodicWorkPolicy. TransmettezrepeatingRequesten tant que paramètrePeriodicWorkRequest.
WorkManager.getInstance().enqueueUniquePeriodicWork(
       RefreshDataWorker.WORK_NAME,
       ExistingPeriodicWorkPolicy.KEEP,
       repeatingRequest)Si des tâches en attente (non terminées) portant le même nom existent, le paramètre ExistingPeriodicWorkPolicy.KEEP permet à WorkManager de conserver la tâche périodique précédente et d'ignorer la nouvelle demande de tâche.
- Au début de la classe DevByteApplication, créez un objetCoroutineScope. TransmettezDispatchers.Defaulten tant que paramètre constructeur.
private val applicationScope = CoroutineScope(Dispatchers.Default)- Dans la classe DevByteApplication, ajoutez une méthode appeléedelayedInit()pour démarrer une coroutine.
private fun delayedInit() {
   applicationScope.launch {
   }
}- Dans la méthode delayedInit(), appelezsetupRecurringWork().
- Déplacez l'initialisation de Timber de la méthode onCreate()vers la méthodedelayedInit().
private fun delayedInit() {
   applicationScope.launch {
       Timber.plant(Timber.DebugTree())
       setupRecurringWork()
   }
}- Dans la classe DevByteApplication, à la fin de la méthodeonCreate(), ajoutez un appel à la méthodedelayedInit().
override fun onCreate() {
   super.onCreate()
   delayedInit()
}- Ouvrez le volet Logcat en bas de la fenêtre Android Studio. Filtrer sur RefreshDataWorker.
- Exécutez l'application. WorkManagerplanifie immédiatement votre tâche récurrente.
 Dans le volet Logcat, notez les instructions de journal qui indiquent que la requête de travail est planifiée, puis exécutée avec succès.
D/RefreshDataWorker: Work request for sync is run I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
Le journal WM-WorkerWrapper s'affiche à partir de la bibliothèque WorkManager. Vous ne pouvez donc pas modifier ce message de journal.
Étape 3 : (Facultatif) Planifiez WorkRequest pour un intervalle minimal
Dans cette étape, vous réduisez l'intervalle de temps de 1 jour à 15 minutes. Cela vous permettra de voir les journaux d'une requête de tâche périodique en action.
- Dans la classe DevByteApplication, à l'intérieur de la méthodesetupRecurringWork(), mettez en commentaire la définitionrepeatingRequestactuelle. Ajoutez une requête de travail avec un intervalle de répétition périodique de15minutes.
// val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
//        .build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
       .build()- Ouvrez le volet Logcat dans Android Studio et filtrez sur RefreshDataWorker. Pour effacer les journaux précédents, cliquez sur l'icône Effacer logcat . .
- Exécutez l'application. WorkManagerplanifie immédiatement votre tâche récurrente. Dans le volet Logcat, notez les journaux : la requête de travail est exécutée une fois toutes les 15 minutes. Patientez 15 minutes pour afficher un autre ensemble de journaux de demandes de travail. Vous pouvez laisser l'application en cours d'exécution ou la fermer. Le gestionnaire de tâches devrait toujours s'exécuter.
 Notez que l'intervalle est parfois inférieur à 15 minutes et parfois supérieur à 15 minutes. (Le moment exact dépend des optimisations de la batterie de l'OS.)
12:44:40 D/RefreshDataWorker: Work request for sync is run 12:44:40 I/WM-WorkerWrapper: Worker result SUCCESS for Work 12:59:24 D/RefreshDataWorker: Work request for sync is run 12:59:24 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:15:03 D/RefreshDataWorker: Work request for sync is run 13:15:03 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:29:22 D/RefreshDataWorker: Work request for sync is run 13:29:22 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:44:26 D/RefreshDataWorker: Work request for sync is run 13:44:26 I/WM-WorkerWrapper: Worker result SUCCESS for Work
 Félicitations ! Vous avez créé un nœud de calcul et planifié la demande de travail avec WorkManager. Il y a cependant un problème : vous n'avez spécifié aucune contrainte. WorkManager planifiera le travail une fois par jour, même si la batterie de l'appareil est faible, s'il est en veille ou s'il n'est pas connecté au réseau. Cela affectera la batterie et les performances de l'appareil, et pourrait nuire à l'expérience utilisateur.
Dans la tâche suivante, vous allez résoudre ce problème en ajoutant des contraintes.
Dans la tâche précédente, vous avez utilisé WorkManager pour planifier une demande de travail. Dans cette tâche, vous allez ajouter des critères pour déterminer quand exécuter le travail.
Lorsque vous définissez WorkRequest, vous pouvez spécifier des contraintes concernant l'exécution de Worker. Par exemple, vous pouvez spécifier que le travail ne doit s'exécuter que lorsque l'appareil est inactif, ou uniquement lorsqu'il est branché et connecté au Wi-Fi. Vous pouvez également spécifier une règle de backoff pour réessayer le travail. Les contraintes acceptées sont les méthodes définies dans Constraints.Builder. Pour en savoir plus, consultez Définir vos demandes de travail.
Étape 1 : Ajoutez un objet "Constraints" et définissez une contrainte
Dans cette étape, vous allez créer un objet Constraints et définir une contrainte sur l'objet, à savoir une contrainte de type réseau. (Il est plus facile de remarquer les journaux avec une seule contrainte. Vous ajouterez d'autres contraintes à une étape ultérieure.)
- Dans la classe DevByteApplication, au début desetupRecurringWork(), définissez unvalde typeConstraints. Utilisez la méthodeConstraints.Builder().
val constraints = Constraints.Builder()Pour résoudre l'erreur, importez androidx.work.Constraints.
- Utilisez la méthode setRequiredNetworkType()pour ajouter une contrainte de type réseau à l'objetconstraints. Utilisez l'énumérationUNMETEREDpour que la requête de travail ne s'exécute que lorsque l'appareil est connecté à un réseau non limité.
.setRequiredNetworkType(NetworkType.UNMETERED)- Utilisez la méthode build()pour générer les contraintes à partir du compilateur.
val constraints = Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .build()Vous devez maintenant définir l'objet Constraints nouvellement créé sur la demande de travail.
- Dans la classe DevByteApplication, à l'intérieur de la méthodesetupRecurringWork(), définissez l'objetConstraintssur la requête de travail périodique,repeatingRequest. Pour définir les contraintes, ajoutez la méthodesetConstraints()au-dessus de l'appel de méthodebuild().
       val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
               .setConstraints(constraints)
               .build()Étape 2 : Exécutez l'application et examinez les journaux
Dans cette étape, vous allez exécuter l'application et remarquer que la requête de travail contrainte est exécutée en arrière-plan à intervalles réguliers.
- Désinstallez l'application de l'appareil ou de l'émulateur pour annuler les tâches précédemment planifiées.
- Ouvrez le volet Logcat dans Android Studio. Dans le volet Logcat, effacez les journaux précédents en cliquant sur l'icône Effacer Logcat  à gauche. Filtrer sur à gauche. Filtrer surwork.
- Désactivez le Wi-Fi sur l'appareil ou l'émulateur pour voir comment fonctionnent les contraintes. Le code actuel ne définit qu'une seule contrainte, indiquant que la requête ne doit s'exécuter que sur un réseau non limité. Comme le Wi-Fi est désactivé, l'appareil n'est connecté à aucun réseau, qu'il soit avec ou sans compteur. Par conséquent, cette contrainte ne sera pas respectée.
- Exécutez l'application et observez le volet Logcat. WorkManagerplanifie immédiatement la tâche en arrière-plan. La tâche n'est pas exécutée, car la contrainte de réseau n'est pas respectée.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
- Activez le Wi-Fi sur l'appareil ou l'émulateur, puis observez le volet Logcat. La tâche en arrière-plan planifiée est désormais exécutée environ toutes les 15 minutes, à condition que la contrainte réseau soit respectée.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled 11:31:47 D/RefreshDataWorker: Work request for sync is run 11:31:47 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 11:46:45 D/RefreshDataWorker: Work request for sync is run 11:46:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:03:05 D/RefreshDataWorker: Work request for sync is run 12:03:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:16:45 D/RefreshDataWorker: Work request for sync is run 12:16:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:31:45 D/RefreshDataWorker: Work request for sync is run 12:31:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:47:05 D/RefreshDataWorker: Work request for sync is run 12:47:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 13:01:45 D/RefreshDataWorker: Work request for sync is run 13:01:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
Étape 3 : Ajoutez d'autres contraintes
À cette étape, vous allez ajouter les contraintes suivantes à PeriodicWorkRequest : 
- La batterie n'est pas faible.
- Recharge de l'appareil.
- Inactivité de l'appareil : disponible uniquement au niveau d'API 23 (Android M) et supérieur.
Implémentez ce qui suit dans la classe DevByteApplication.
- Dans la classe DevByteApplication, à l'intérieur de la méthodesetupRecurringWork(), indiquez que la requête de travail ne doit s'exécuter que si la batterie n'est pas faible. Ajoutez la contrainte avant l'appel de la méthodebuild()et utilisez la méthodesetRequiresBatteryNotLow().
.setRequiresBatteryNotLow(true)- Mettez à jour la requête de travail pour qu'elle ne s'exécute que lorsque l'appareil est en charge. Ajoutez la contrainte avant l'appel de la méthode build()et utilisez la méthodesetRequiresCharging().
.setRequiresCharging(true)- Mettez à jour la requête de travail pour qu'elle ne s'exécute que lorsque l'appareil est inactif. Ajoutez la contrainte avant l'appel de la méthode build()et utilisez la méthodesetRequiresDeviceIdle(). Cette contrainte exécute la requête de travail uniquement lorsque l'utilisateur n'utilise pas activement l'appareil. Cette fonctionnalité n'est disponible que dans Android 6.0 (Marshmallow) et versions ultérieures. Ajoutez donc une condition pour la version du SDKMet versions ultérieures.
.apply {
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
       setRequiresDeviceIdle(true)
   }
}Voici la définition complète de l'objet constraints.
val constraints = Constraints.Builder()
       .setRequiredNetworkType(NetworkType.UNMETERED)
       .setRequiresBatteryNotLow(true)
       .setRequiresCharging(true)
       .apply {
           if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
               setRequiresDeviceIdle(true)
           }
       }
       .build()- Dans la méthode setupRecurringWork(), rétablissez l'intervalle de requête sur "une fois par jour".
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
       .setConstraints(constraints)
       .build()Voici l'implémentation complète de la méthode setupRecurringWork(), avec un journal pour vous permettre de suivre la planification de la requête de travail périodique. 
private fun setupRecurringWork() {
       val constraints = Constraints.Builder()
               .setRequiredNetworkType(NetworkType.UNMETERED)
               .setRequiresBatteryNotLow(true)
               .setRequiresCharging(true)
               .apply {
                   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                       setRequiresDeviceIdle(true)
                   }
               }
               .build()
       val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
               .setConstraints(constraints)
               .build()
       
       Timber.d("Periodic Work request for sync is scheduled")
       WorkManager.getInstance().enqueueUniquePeriodicWork(
               RefreshDataWorker.WORK_NAME,
               ExistingPeriodicWorkPolicy.KEEP,
               repeatingRequest)
   }- Pour supprimer la demande de travail précédemment planifiée, désinstallez l'application DevBytes de votre appareil ou émulateur.
- Exécutez l'application. WorkManagerplanifie immédiatement la requête de travail. La requête de tâche s'exécute une fois par jour, lorsque toutes les contraintes sont remplies.
- Cette demande de travail s'exécutera en arrière-plan tant que l'application sera installée, même si elle n'est pas en cours d'exécution. Pour cette raison, vous devez désinstaller l'application du téléphone.
Bien joué ! Vous avez implémenté et planifié une requête de travail économe en batterie pour le préchargement quotidien des vidéos dans l'application DevBytes. WorkManager planifiera et exécutera le travail, en optimisant les ressources système. Vos utilisateurs et leurs batteries vous remercieront.
Projet Android Studio : DevBytesWorkManager.
- L'API WorkManagerfacilite la planification des tâches asynchrones différables qui doivent être exécutées de manière fiable.
- La plupart des applications réelles doivent effectuer des tâches de longue durée en arrière-plan. Pour planifier une tâche en arrière-plan de manière efficace et optimisée, utilisez WorkManager.
- Les principales classes de la bibliothèque WorkManagersontWorker,WorkRequestetWorkManager.
- La classe Workerreprésente une unité de travail. Pour implémenter la tâche en arrière-plan, étendez la classeWorkeret remplacez la méthodedoWork().
- La classe WorkRequestreprésente une requête pour effectuer une unité de travail.WorkRequestest la classe de base permettant de spécifier les paramètres des tâches que vous planifiez dansWorkManager.
- Il existe deux implémentations concrètes de la classe WorkRequest:OneTimeWorkRequestpour les tâches ponctuelles etPeriodicWorkRequestpour les demandes de travail périodiques.
- Lorsque vous définissez WorkRequest, vous pouvez spécifierConstraintspour indiquer quandWorkerdoit s'exécuter. Les contraintes incluent des éléments tels que la connexion de l'appareil à une prise électrique, son état d'inactivité ou la connexion au Wi-Fi.
- Pour ajouter des contraintes à WorkRequest, utilisez les méthodes d'ensemble listées dans la documentationConstraints.Builder. Par exemple, pour indiquer queWorkRequestne doit pas s'exécuter si la batterie de l'appareil est faible, utilisez la méthode de définitionsetRequiresBatteryNotLow().
- Après avoir défini l'WorkRequest, transmettez la tâche au système Android. Pour ce faire, planifiez la tâche à l'aide de l'une des méthodesenqueuedeWorkManager.
- Le délai exact d'exécution du Workerdépend des contraintes utilisées dans leWorkRequestet des optimisations du système.WorkManagerest conçu pour offrir le meilleur comportement possible, compte tenu de ces restrictions.
Cours Udacity :
Documentation pour les développeurs Android :
- Définir vos WorkRequests
- WorkManager
- Premiers pas avec WorkManager
- Travaux récurrents
- Guide relatif au traitement en arrière-plan
Autre :
Cette section répertorie les devoirs possibles pour les élèves qui suivent cet atelier de programmation dans le cadre d'un cours animé par un enseignant. Il revient à l'enseignant d'effectuer les opérations suivantes :
- Attribuer des devoirs si nécessaire
- Indiquer aux élèves comment rendre leurs devoirs
- Noter les devoirs
Les enseignants peuvent utiliser ces suggestions autant qu'ils le souhaitent, et ne doivent pas hésiter à attribuer d'autres devoirs aux élèves s'ils le jugent nécessaire.
Si vous suivez cet atelier de programmation par vous-même, n'hésitez pas à utiliser ces devoirs pour tester vos connaissances.
Question 1
Quelles sont les implémentations concrètes de la classe WorkRequest ? 
▢ OneTimeWorkPeriodicRequest
▢ OneTimeWorkRequest et PeriodicWorkRequest
▢ OneTimeWorkRequest et RecurringWorkRequest
▢ OneTimeOffWorkRequest et RecurringWorkRequest
Question 2
Parmi les classes suivantes, laquelle WorkManager utilise-t-il pour planifier la tâche en arrière-plan sur l'API 23 et versions supérieures ? 
▢ JobScheduler uniquement
▢ BroadcastReceiver et AlarmManager
▢ AlarmManager et JobScheduler
▢ Scheduler et BroadcastReceiver
Question 3
Quelle API utilisez-vous pour ajouter des contraintes à une WorkRequest ? 
▢ setConstraints()
▢ addConstraints()
▢ setConstraint()
▢ addConstraintsToWorkRequest()
Passez à la leçon suivante : 
Pour obtenir des liens vers d'autres ateliers de programmation de ce cours, consultez la page de destination des ateliers de programmation Principes de base d'Android en Kotlin.