Android WorkManager en 2026 : Tâches en Arrière-plan, Contraintes et Questions d'Entretien

Guide complet sur WorkManager pour Android en 2026 : création de Workers, contraintes d'exécution, chaînage de tâches et questions techniques d'entretien.

Android WorkManager architecture diagram showing background task scheduling

WorkManager représente la solution officielle de Jetpack pour l'exécution de tâches en arrière-plan garanties sur Android. Contrairement aux threads classiques ou aux coroutines qui disparaissent avec le processus de l'application, WorkManager persiste les travaux planifiés et les exécute même après un redémarrage de l'appareil. La version 2.11.2 (stable, mars 2026) prend en charge les API 23+ et sélectionne automatiquement le mécanisme sous-jacent optimal (JobScheduler, AlarmManager) selon la version Android du dispositif.

Quand utiliser WorkManager

WorkManager convient aux tâches différables nécessitant une exécution garantie : synchronisation de données, téléversement de fichiers, traitement d'images. Pour les opérations immédiates sans garantie de survie au processus, les coroutines Kotlin restent préférables.

Configuration de WorkManager 2.11 dans un Projet Kotlin

L'intégration de WorkManager commence par l'ajout de la dépendance dans le fichier Gradle. La version 2.11+ requiert minSdk 23 et compileSdk 33 minimum.

build.gradle.kts (module app)gradle
dependencies {
    val workVersion = "2.11.2"
    implementation("androidx.work:work-runtime-ktx:$workVersion")
    // Optionnel : pour les tests
    androidTestImplementation("androidx.work:work-testing:$workVersion")
}

L'artefact work-runtime-ktx inclut les extensions Kotlin et le support des coroutines via CoroutineWorker. WorkManager s'initialise automatiquement grâce à un ContentProvider déclaré dans le manifeste de la bibliothèque.

Création d'un Worker Simple avec doWork()

Une classe Worker hérite de la classe de base et surcharge la méthode doWork(). Le système exécute cette méthode sur un thread d'arrière-plan dédié.

SyncWorker.ktkotlin
class SyncWorker(
    context: Context,
    params: WorkerParameters
) : Worker(context, params) {

    override fun doWork(): Result {
        // Lecture des données d'entrée
        val userId = inputData.getString("user_id") ?: return Result.failure()
        
        return try {
            // Exécution de la synchronisation
            val syncService = SyncService.getInstance(applicationContext)
            syncService.syncUserData(userId)
            Result.success()
        } catch (e: IOException) {
            // Nouvelle tentative sur erreur réseau
            Result.retry()
        } catch (e: Exception) {
            // Échec permanent
            Result.failure()
        }
    }
}

Trois résultats possibles existent : Result.success() indique la complétion réussie, Result.failure() arrête les nouvelles tentatives, et Result.retry() replanifie selon la politique de backoff configurée.

Utilisation de CoroutineWorker pour les Fonctions Suspend

Lorsque le travail implique des fonctions suspend (appels Retrofit, requêtes Room), CoroutineWorker simplifie considérablement le code en éliminant les callbacks imbriqués.

UploadWorker.ktkotlin
class UploadWorker(
    context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        val imageUri = inputData.getString("image_uri")
            ?: return Result.failure()
        
        // Rapport de progression (visible dans les observateurs WorkInfo)
        setProgress(workDataOf("status" to "compression"))
        
        val compressed = ImageCompressor.compress(imageUri)
        
        setProgress(workDataOf("status" to "téléversement"))
        
        return try {
            val api = RetrofitClient.uploadService
            api.uploadImage(compressed)
            Result.success()
        } catch (e: HttpException) {
            if (e.code() in 500..599) Result.retry()
            else Result.failure()
        }
    }
}

La méthode setProgress() permet de communiquer l'état d'avancement aux observateurs de l'interface utilisateur, particulièrement utile pour les opérations longues comme les téléversements de fichiers volumineux.

Définition des Contraintes d'Exécution

Les contraintes permettent de spécifier les conditions requises pour l'exécution du travail. WorkManager attend que toutes les contraintes soient satisfaites avant de lancer le Worker.

kotlin
// Contraintes pour une synchronisation de données
val constraints = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.CONNECTED)
    .setRequiresBatteryNotLow(true)
    .setRequiresStorageNotLow(true)
    .build()

val syncRequest = OneTimeWorkRequestBuilder<SyncWorker>()
    .setConstraints(constraints)
    .setInputData(workDataOf("user_id" to userId))
    .build()

WorkManager.getInstance(context).enqueue(syncRequest)

Les contraintes disponibles incluent le type de réseau (CONNECTED, UNMETERED, METERED, NOT_ROAMING), l'état de la batterie, le stockage disponible, et l'état de charge de l'appareil. Sur Android 7+, la contrainte setRequiresDeviceIdle(true) permet d'attendre que l'appareil soit inactif.

Configuration des Politiques de Backoff

Lorsqu'un Worker retourne Result.retry(), WorkManager replanifie automatiquement l'exécution selon une politique de backoff configurable.

kotlin
val uploadRequest = OneTimeWorkRequestBuilder<UploadWorker>()
    .setBackoffCriteria(
        BackoffPolicy.EXPONENTIAL,
        WorkRequest.MIN_BACKOFF_MILLIS,
        TimeUnit.MILLISECONDS
    )
    .build()

Deux politiques sont disponibles : LINEAR (délai constant entre les tentatives) et EXPONENTIAL (délai doublant à chaque tentative). Le délai minimum est de 10 secondes, et le maximum atteint 5 heures.

Chaînage de Travaux Séquentiels et Parallèles

WorkManager permet de créer des workflows complexes en chaînant plusieurs Workers. Les travaux peuvent s'exécuter séquentiellement ou en parallèle.

kotlin
// Workflow : compression -> téléversement -> notification
val compressWork = OneTimeWorkRequestBuilder<CompressWorker>().build()
val uploadWork = OneTimeWorkRequestBuilder<UploadWorker>().build()
val notifyWork = OneTimeWorkRequestBuilder<NotificationWorker>().build()

WorkManager.getInstance(context)
    .beginWith(compressWork)
    .then(uploadWork)
    .then(notifyWork)
    .enqueue()

Pour l'exécution parallèle, la méthode beginWith() accepte une liste de WorkRequests :

kotlin
// Téléchargement parallèle de plusieurs ressources
val downloads = listOf(
    OneTimeWorkRequestBuilder<DownloadWorker>()
        .setInputData(workDataOf("url" to url1)).build(),
    OneTimeWorkRequestBuilder<DownloadWorker>()
        .setInputData(workDataOf("url" to url2)).build(),
    OneTimeWorkRequestBuilder<DownloadWorker>()
        .setInputData(workDataOf("url" to url3)).build()
)

val mergeWork = OneTimeWorkRequestBuilder<MergeWorker>().build()

WorkManager.getInstance(context)
    .beginWith(downloads)
    .then(mergeWork)
    .enqueue()

Travaux Uniques et Stratégies de Remplacement

Les travaux uniques garantissent qu'une seule instance d'un travail particulier existe dans la file d'attente, évitant les duplications lors d'appels répétés.

kotlin
val syncRequest = OneTimeWorkRequestBuilder<SyncWorker>().build()

WorkManager.getInstance(context).enqueueUniqueWork(
    "user_sync",
    ExistingWorkPolicy.REPLACE,
    syncRequest
)

Trois politiques existent : REPLACE annule le travail existant et le remplace, KEEP conserve le travail existant et ignore le nouveau, APPEND ajoute le nouveau travail à la chaîne existante.

Travaux Périodiques avec PeriodicWorkRequest

Pour les tâches récurrentes comme la synchronisation de données ou le nettoyage de cache, PeriodicWorkRequest offre une planification automatique.

kotlin
val periodicSync = PeriodicWorkRequestBuilder<SyncWorker>(
    repeatInterval = 1,
    repeatIntervalTimeUnit = TimeUnit.HOURS,
    flexTimeInterval = 15,
    flexTimeIntervalUnit = TimeUnit.MINUTES
)
    .setConstraints(constraints)
    .build()

WorkManager.getInstance(context).enqueueUniquePeriodicWork(
    "periodic_sync",
    ExistingPeriodicWorkPolicy.UPDATE,
    periodicSync
)

L'intervalle minimum est de 15 minutes. Le paramètre flexTimeInterval définit une fenêtre durant laquelle le travail peut s'exécuter, permettant au système d'optimiser la consommation de batterie.

Observation de l'État des Travaux

L'observation des travaux permet de mettre à jour l'interface utilisateur en fonction de la progression et du résultat.

kotlin
// Dans un ViewModel
val workInfo: LiveData<WorkInfo> = WorkManager
    .getInstance(application)
    .getWorkInfoByIdLiveData(uploadRequest.id)

// Observation dans un Fragment
viewModel.workInfo.observe(viewLifecycleOwner) { info ->
    when (info.state) {
        WorkInfo.State.RUNNING -> {
            val progress = info.progress.getString("status")
            updateProgressUI(progress)
        }
        WorkInfo.State.SUCCEEDED -> showSuccessUI()
        WorkInfo.State.FAILED -> showErrorUI()
        else -> { /* En attente ou annulé */ }
    }
}

Prêt à réussir tes entretiens Android ?

Entraîne-toi avec nos simulateurs interactifs, fiches express et tests techniques.

Questions d'Entretien Technique sur WorkManager

Les entretiens techniques Android abordent fréquemment WorkManager. Voici les questions les plus courantes avec leurs réponses détaillées.

Quelle est la différence entre Worker et CoroutineWorker ?

Worker exécute doWork() sur un thread d'arrière-plan de manière synchrone. CoroutineWorker permet d'utiliser des fonctions suspend et s'exécute par défaut sur Dispatchers.Default. Pour les opérations asynchrones impliquant des appels réseau ou des accès base de données avec Room, CoroutineWorker est préférable.

Comment WorkManager garantit-il l'exécution des travaux ?

WorkManager persiste les informations de travail dans une base de données SQLite interne. Au démarrage de l'application ou lors du boot de l'appareil (si la permission RECEIVE_BOOT_COMPLETED est accordée), WorkManager restaure les travaux en attente et les replanifie.

Quelle est la durée maximale d'exécution d'un Worker ?

Un Worker dispose de 10 minutes maximum pour compléter son travail sur la plupart des appareils. Ce délai peut varier selon les fabricants et les optimisations de batterie. Pour les travaux longs, il faut utiliser setForeground() avec une notification de premier plan.

Comment transmettre des données entre Workers chaînés ?

Le Worker qui termine peut retourner des données via Result.success(outputData). Le Worker suivant dans la chaîne accède à ces données via inputData. Pour les chaînes parallèles fusionnant vers un seul Worker, un InputMerger combine les sorties.

kotlin
override fun doWork(): Result {
    val processedId = processData()
    val output = workDataOf("processed_id" to processedId)
    return Result.success(output)
}

Comment tester un Worker ?

La bibliothèque work-testing fournit TestListenableWorkerBuilder pour les tests unitaires et WorkManagerTestInitHelper pour les tests d'intégration.

kotlin
@Test
fun testSyncWorker() = runTest {
    val context = ApplicationProvider.getApplicationContext<Context>()
    val worker = TestListenableWorkerBuilder<SyncWorker>(context)
        .setInputData(workDataOf("user_id" to "123"))
        .build()
    
    val result = worker.doWork()
    
    assertThat(result).isEqualTo(ListenableWorker.Result.success())
}

Conclusion

WorkManager constitue la pierre angulaire de la gestion des tâches en arrière-plan sur Android moderne. Sa capacité à persister les travaux, respecter les contraintes système et s'adapter aux différentes versions Android en fait un outil indispensable. La maîtrise des concepts de contraintes, de chaînage et de politiques de backoff permet de construire des applications robustes capables de gérer efficacement les opérations asynchrones complexes, même dans des conditions réseau ou d'énergie défavorables.

Défi du jour

Tu saurais repérer le bug en Android ?

Un vrai bout de code, un bug caché, une tentative par jour. Sans compte pour essayer.

Anthony Fillion-Maillet

Écrit par

Anthony Fillion-Maillet

Fondateur de SharpSkill

Développeur fullstack depuis plus de 10 ans. Il dirige SharpSkill et répond de tout ce qui y est publié.

Mis à jour le 22 août 2026

Tags

#android
#workmanager
#kotlin
#jetpack
#background-tasks

Partager

Articles similaires