Especialista em Tarefas em Segundo Plano no Android
Especialista em execução em segundo plano no Android com WorkManager, Foreground Services, tratamento do Modo Doze e processamento eficiente de bateria.
Gatilhos de Ativação
Ative em: "WorkManager", "tarefa em segundo plano Android", "Foreground Service", "Modo Doze", "otimização de bateria", "trabalho periódico", "sincronização em segundo plano", "JobScheduler", "processamento em segundo plano Android"
NÃO para: tarefas em segundo plano iOS → swiftui-data-flow-expert | tarefas em segundo plano React Native → mobile-offline-sync-architect | arquitetura de UI → jetpack-compose-navigation-expert
Início Rápido
- Escolha a API correta — WorkManager para trabalho adiável, Foreground Service para tarefas contínuas visíveis ao usuário, corrotinas para trabalho assíncrono curto
- Defina workers — estenda
CoroutineWorkercom funçõessuspendpara código assíncrono limpo - Configure restrições — tipo de rede, nível de bateria, requisitos de armazenamento
- Lide com Doze e App Standby — use WorkManager (não AlarmManager) para agendamento compatível com Doze
- Teste com adb — force o Modo Doze e verifique se o trabalho é executado quando as restrições são atendidas
Capacidades Principais
| Domínio | Tecnologias |
|---|---|
| Trabalho Adiável | WorkManager 2.10, OneTimeWorkRequest, PeriodicWorkRequest |
| Primeiro Plano | Tipos de Foreground Service (dataSync, location, mediaPlayback, shortService) |
| Restrições | NetworkType, BatteryNotLow, StorageNotLow, DeviceIdle |
| Encadeamento | WorkContinuation, cadeias paralelas, políticas de trabalho único |
| Testes | TestWorkerBuilder, TestListenableWorkerBuilder, WorkManagerTestInitHelper |
Padrões Arquiteturais
Árvore de Decisão do WorkManager
A tarefa é iniciada pelo usuário e precisa ser concluída?
├─ SIM → É curta (< 10 min)?
│ ├─ SIM → Foreground Service (tipo shortService)
│ └─ NÃO → Foreground Service (dataSync, location, etc.)
│
└─ NÃO → É adiável?
├─ SIM → WorkManager
│ ├─ Única? → OneTimeWorkRequest
│ └─ Periódica? → PeriodicWorkRequest (intervalo mínimo de 15 min)
│
└─ NÃO → É enquanto o aplicativo está visível?
├─ SIM → CoroutineScope (viewModelScope ou lifecycleScope)
└─ NÃO → Provavelmente você precisa do WorkManager mesmo assim
CoroutineWorker com Retry e Progresso
@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 {
// Reporte progresso para observação da 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 exponencial por padrão
} else {
Result.failure(workDataOf("error" to e.message))
}
}
}
override suspend fun getForegroundInfo(): ForegroundInfo {
return ForegroundInfo(
NOTIFICATION_ID,
notificationHelper.createSyncNotification()
)
}
}
Agendamento com Restrições e Encadeamento
// Agende sincronização periódica a cada 1 hora (mínimo 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, // Não reinicie se já estiver agendado
syncRequest
)
// Encadeamento: baixar → processar → enviar (sequencial)
WorkManager.getInstance(context)
.beginWith(downloadWork)
.then(processWork)
.then(uploadWork)
.enqueue()
Anti-Padrões
- AlarmManager para trabalho adiável — alarmes do AlarmManager não são compatíveis com Doze e drenam a bateria. Use WorkManager, que respeita Doze, App Standby e economia de bateria.
- Background Service sem notificação em primeiro plano — Android 12+ mata serviços em segundo plano. Use Foreground Service com declaração de tipo adequada ou WorkManager.
- PeriodicWork com menos de 15 minutos — WorkManager impõe um intervalo mínimo de 15 minutos. Para trabalhos mais frequentes, use Foreground Service ou corrotinas com consciência de ciclo de vida.
- Não declarar o tipo de foreground service — Android 14+ exige
foregroundServiceTypeexplícito no manifesto. Omiti-lo causaSecurityException. - Ignorar observação do trabalho — iniciar o trabalho sem mostrar progresso aos usuários. Observe
WorkInfoviagetWorkInfoByIdLiveData()ougetWorkInfoByIdFlow()para atualizar a UI.
Checklist de Qualidade
[ ] WorkManager usado para tarefas adiáveis em segundo plano (não AlarmManager)
[ ] Foreground Service declarado com o tipo correto no AndroidManifest
[ ] Restrições configuradas (rede, bateria, armazenamento)
[ ] Política de retry com backoff para falhas transitórias
[ ] Política de trabalho único definida para trabalho periódico/único
[ ] Progresso do trabalho observável a partir da UI
[ ] Modo Doze testado via adb: `adb shell dumpsys deviceidle force-idle`
[ ] Otimização de bateria testada: `adb shell am set-inactive <package> true`
[ ] Workers testados com TestWorkerBuilder
[ ] Canais de notificação criados para notificações de foreground service
[ ] Cadeias de trabalho lidam com falhas parciais de forma graciosa
[ ] Trabalho em segundo plano respeita a preferência do usuário por economia de bateria