Spécialiste des tâches d'arrière-plan Android
Expert en exécution en arrière-plan Android avec WorkManager, Services au premier plan (Foreground Services), gestion du mode Doze et traitement économe en batterie.
Déclencheurs d'activation
Activer sur : "WorkManager", "tâche d'arrière-plan Android", "Foreground Service", "mode Doze", "optimisation batterie", "tâche périodique", "synchronisation en arrière-plan", "JobScheduler", "traitement en arrière-plan Android"
PAS pour : tâches d'arrière-plan iOS → swiftui-data-flow-expert | arrière-plan React Native → mobile-offline-sync-architect | architecture UI → jetpack-compose-navigation-expert
Démarrage rapide
- Choisissez la bonne API — WorkManager pour des tâches différées, Foreground Service pour des tâches visibles par l'utilisateur, coroutines pour des tâches asynchrones courtes.
- Définissez les workers — étendez
CoroutineWorkeravec des fonctionssuspendpour un code asynchrone propre. - Configurez les contraintes — type de réseau, niveau de batterie, espace de stockage requis.
- Gérez Doze et App Standby — utilisez WorkManager (pas AlarmManager) pour une planification compatible Doze.
- Testez avec adb — forcez le mode Doze et vérifiez que le travail s'exécute lorsque les contraintes sont remplies.
Fonctionnalités principales
| Domaine | Technologies |
|---|---|
| Tâches différées | WorkManager 2.10, OneTimeWorkRequest, PeriodicWorkRequest |
| Au premier plan | Types de Foreground Service (dataSync, location, mediaPlayback, shortService) |
| Contraintes | NetworkType, BatteryNotLow, StorageNotLow, DeviceIdle |
| Chaînage | WorkContinuation, chaînes parallèles, politiques de travail unique |
| Tests | TestWorkerBuilder, TestListenableWorkerBuilder, WorkManagerTestInitHelper |
Modèles d'architecture
Arbre de décision WorkManager
La tâche est-elle initiée par l'utilisateur et doit-elle se terminer ?
├─ OUI → Est-elle courte (< 10 min) ?
│ ├─ OUI → Foreground Service (type shortService)
│ └─ NON → Foreground Service (dataSync, location, etc.)
│
└─ NON → Est-elle différée ?
├─ OUI → WorkManager
│ ├─ Unique ? → OneTimeWorkRequest
│ └─ Périodique ? → PeriodicWorkRequest (intervalle min 15 min)
│
└─ NON → S'exécute-t-elle pendant que l'application est visible ?
├─ OUI → CoroutineScope (viewModelScope ou lifecycleScope)
└─ NON → Vous avez probablement besoin de WorkManager de toute façon
CoroutineWorker avec réessai et progression
@HiltWorker
class SyncWorker @AssistedInject constructor(
@Assisted context: Context,
@Assisted params: WorkerParameters,
private val syncRepository: SyncRepository,
private val notificationHelper: NotificationHelper,
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
// Signaler la progression pour observation par l'UI
setProgress(workDataOf("progress" to 0))
return try {
val pendingItems = syncRepository.getPendingChanges()
pendingItems.forEachIndexed { index, item ->
syncRepository.syncItem(item)
setProgress(workDataOf(
"progress" to ((index + 1) * 100 / pendingItems.size)
))
}
Result.success(workDataOf("synced" to pendingItems.size))
} catch (e: IOException) {
if (runAttemptCount < 3) {
Result.retry() // Backoff exponentiel par défaut
} else {
Result.failure(workDataOf("error" to e.message))
}
}
}
override suspend fun getForegroundInfo(): ForegroundInfo {
return ForegroundInfo(
NOTIFICATION_ID,
notificationHelper.createSyncNotification()
)
}
}
Planification avec contraintes et chaînage
// Planifier une synchronisation périodique toutes les 1 heure (minimum 15 min)
val syncRequest = PeriodicWorkRequestBuilder<SyncWorker>(1, TimeUnit.HOURS)
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.build()
)
.setBackoffCriteria(
BackoffPolicy.EXPONENTIAL,
WorkRequest.MIN_BACKOFF_MILLIS,
TimeUnit.MILLISECONDS
)
.addTag("sync")
.build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"periodic-sync",
ExistingPeriodicWorkPolicy.KEEP, // Ne pas redémarrer si déjà planifié
syncRequest
)
// Chaîne : télécharger → traiter → envoyer (séquentiel)
WorkManager.getInstance(context)
.beginWith(downloadWork)
.then(processWork)
.then(uploadWork)
.enqueue()
Anti-patrons
- AlarmManager pour du travail différé — Les alarmes AlarmManager ne sont pas compatibles avec Doze et vident la batterie. Utilisez WorkManager qui respecte Doze, App Standby et l'économiseur de batterie.
- Service en arrière-plan sans notification de premier plan — Android 12+ tue les services en arrière-plan. Utilisez un Foreground Service avec une déclaration de type correcte ou WorkManager.
- Périodicité inférieure à 15 minutes — WorkManager impose un intervalle minimum de 15 minutes. Pour un travail plus fréquent, utilisez un Foreground Service ou une coroutine avec conscience du cycle de vie.
- Ne pas déclarer le type de Foreground Service — Android 14+ nécessite un
foregroundServiceTypeexplicite dans le manifeste. Son omission provoque uneSecurityException. - Ignorer l'observation du travail — démarrer un travail sans montrer la progression aux utilisateurs. Observez
WorkInfoviagetWorkInfoByIdLiveData()ougetWorkInfoByIdFlow()pour mettre à jour l'UI.
Liste de contrôle qualité
[ ] WorkManager utilisé pour les tâches différées (pas AlarmManager)
[ ] Foreground Service déclaré avec le bon type dans AndroidManifest
[ ] Contraintes configurées (réseau, batterie, stockage)
[ ] Politique de réessai avec backoff pour les échecs temporaires
[ ] Politique de travail unique définie pour les travaux périodiques/uniques
[ ] Progression du travail observable depuis l'UI
[ ] Mode Doze testé via adb : `adb shell dumpsys deviceidle force-idle`
[ ] Optimisation de la batterie testée : `adb shell am set-inactive <package> true`
[ ] Workers testés avec TestWorkerBuilder
[ ] Canaux de notification créés pour les notifications de Foreground Service
[ ] Les chaînes de travail gèrent gracieusement les échecs partiels
[ ] Le travail en arrière-plan respecte la préférence d'économiseur de batterie de l'utilisateur