Android WorkManager em 2026: Tarefas em Segundo Plano, Restrições e Perguntas de Entrevista

Guia completo sobre WorkManager para Android em 2026: criação de Workers, restrições de execução, encadeamento de tarefas e perguntas técnicas de entrevista.

Android WorkManager architecture diagram showing background task scheduling

WorkManager representa a solução oficial do Jetpack para executar tarefas em segundo plano garantidas no Android. Diferentemente das threads convencionais ou corrotinas que desaparecem quando o processo do aplicativo termina, o WorkManager persiste os trabalhos agendados e os executa mesmo após a reinicialização do dispositivo. A versão 2.11.2 (estável, março de 2026) suporta API 23+ e seleciona automaticamente o mecanismo subjacente ideal (JobScheduler, AlarmManager) conforme a versão Android do dispositivo.

Quando usar WorkManager

WorkManager é ideal para tarefas adiáveis que requerem execução garantida: sincronização de dados, upload de arquivos, processamento de imagens. Para operações imediatas sem garantia de sobrevivência ao processo, as corrotinas do Kotlin continuam sendo preferíveis.

Configuração do WorkManager 2.11 em um Projeto Kotlin

A integração do WorkManager começa adicionando a dependência no arquivo Gradle. A versão 2.11+ requer minSdk 23 e compileSdk 33 como mínimo.

build.gradle.kts (módulo app)gradle
dependencies {
    val workVersion = "2.11.2"
    implementation("androidx.work:work-runtime-ktx:$workVersion")
    // Opcional: para testes
    androidTestImplementation("androidx.work:work-testing:$workVersion")
}

O artefato work-runtime-ktx inclui extensões Kotlin e suporte a corrotinas através do CoroutineWorker. O WorkManager se inicializa automaticamente por meio de um ContentProvider declarado no manifesto da biblioteca.

Criação de um Worker Simples com doWork()

Uma classe Worker herda da classe base e sobrescreve o método doWork(). O sistema executa esse método em uma thread de segundo plano dedicada.

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

    override fun doWork(): Result {
        // Leitura dos dados de entrada
        val userId = inputData.getString("user_id") ?: return Result.failure()
        
        return try {
            // Execução da sincronização
            val syncService = SyncService.getInstance(applicationContext)
            syncService.syncUserData(userId)
            Result.success()
        } catch (e: IOException) {
            // Tentar novamente em caso de erro de rede
            Result.retry()
        } catch (e: Exception) {
            // Falha permanente
            Result.failure()
        }
    }
}

Existem três resultados possíveis: Result.success() indica conclusão bem-sucedida, Result.failure() interrompe as novas tentativas, e Result.retry() reagenda conforme a política de backoff configurada.

Uso do CoroutineWorker para Funções Suspend

Quando o trabalho envolve funções suspend (chamadas Retrofit, consultas Room), o CoroutineWorker simplifica consideravelmente o código eliminando callbacks aninhados.

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()
        
        // Relatório de progresso (visível nos observadores de WorkInfo)
        setProgress(workDataOf("status" to "comprimindo"))
        
        val compressed = ImageCompressor.compress(imageUri)
        
        setProgress(workDataOf("status" to "enviando"))
        
        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()
        }
    }
}

O método setProgress() permite comunicar o estado de progresso aos observadores da interface do usuário, particularmente útil para operações longas como upload de arquivos grandes.

Definição de Restrições de Execução

As restrições permitem especificar as condições necessárias para a execução do trabalho. O WorkManager aguarda até que todas as restrições sejam satisfeitas antes de iniciar o Worker.

kotlin
// Restrições para sincronização de dados
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)

As restrições disponíveis incluem o tipo de rede (CONNECTED, UNMETERED, METERED, NOT_ROAMING), o estado da bateria, o armazenamento disponível e o estado de carregamento do dispositivo. No Android 7+, a restrição setRequiresDeviceIdle(true) permite aguardar até que o dispositivo esteja inativo.

Configuração de Políticas de Backoff

Quando um Worker retorna Result.retry(), o WorkManager reagenda automaticamente a execução conforme uma política de backoff configurável.

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

Existem duas políticas disponíveis: LINEAR (atraso constante entre tentativas) e EXPONENTIAL (atraso que dobra a cada tentativa). O atraso mínimo é de 10 segundos, e o máximo atinge 5 horas.

Encadeamento de Trabalhos Sequenciais e Paralelos

O WorkManager permite criar fluxos de trabalho complexos encadeando múltiplos Workers. Os trabalhos podem ser executados sequencial ou paralelamente.

kotlin
// Fluxo: compressão -> upload -> notificação
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()

Para execução paralela, o método beginWith() aceita uma lista de WorkRequests:

kotlin
// Download paralelo de múltiplos recursos
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()

Trabalhos Únicos e Estratégias de Substituição

Os trabalhos únicos garantem que apenas uma instância de um trabalho particular exista na fila, evitando duplicações durante chamadas repetidas.

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

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

Existem três políticas: REPLACE cancela o trabalho existente e o substitui, KEEP mantém o trabalho existente e ignora o novo, APPEND adiciona o novo trabalho à cadeia existente.

Trabalhos Periódicos com PeriodicWorkRequest

Para tarefas recorrentes como sincronização de dados ou limpeza de cache, o PeriodicWorkRequest oferece agendamento automático.

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
)

O intervalo mínimo é de 15 minutos. O parâmetro flexTimeInterval define uma janela durante a qual o trabalho pode ser executado, permitindo que o sistema otimize o consumo de bateria.

Observação do Estado dos Trabalhos

A observação dos trabalhos permite atualizar a interface do usuário conforme o progresso e o resultado.

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

// Observação em um 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 -> { /* Em espera ou cancelado */ }
    }
}

Pronto para mandar bem nas entrevistas de Android?

Pratique com nossos simuladores interativos, flashcards e testes tecnicos.

Perguntas de Entrevista Técnica sobre WorkManager

As entrevistas técnicas de Android frequentemente abordam o WorkManager. A seguir, as perguntas mais comuns com suas respostas detalhadas.

Qual é a diferença entre Worker e CoroutineWorker?

Worker executa doWork() em uma thread de segundo plano de forma síncrona. CoroutineWorker permite utilizar funções suspend e é executado por padrão em Dispatchers.Default. Para operações assíncronas envolvendo chamadas de rede ou acessos a banco de dados com Room, o CoroutineWorker é preferível.

Como o WorkManager garante a execução dos trabalhos?

O WorkManager persiste as informações de trabalho em um banco de dados SQLite interno. Ao iniciar o aplicativo ou durante a inicialização do dispositivo (se a permissão RECEIVE_BOOT_COMPLETED estiver concedida), o WorkManager restaura os trabalhos pendentes e os reagenda.

Qual é a duração máxima de execução de um Worker?

Um Worker dispõe de no máximo 10 minutos para completar seu trabalho na maioria dos dispositivos. Esse tempo pode variar conforme os fabricantes e as otimizações de bateria. Para trabalhos longos, deve-se utilizar setForeground() com uma notificação em primeiro plano.

Como transmitir dados entre Workers encadeados?

O Worker que termina pode retornar dados através de Result.success(outputData). O próximo Worker na cadeia acessa esses dados via inputData. Para cadeias paralelas que convergem para um único Worker, um InputMerger combina as saídas.

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

Como testar um Worker?

A biblioteca work-testing fornece TestListenableWorkerBuilder para testes unitários e WorkManagerTestInitHelper para testes de integração.

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())
}

Conclusão

O WorkManager constitui a base fundamental da gestão de tarefas em segundo plano no Android moderno. Sua capacidade de persistir trabalhos, respeitar restrições do sistema e se adaptar às diferentes versões do Android o torna uma ferramenta indispensável. O domínio dos conceitos de restrições, encadeamento e políticas de backoff permite construir aplicativos robustos capazes de gerenciar eficientemente operações assíncronas complexas, mesmo em condições de rede ou energia desfavoráveis.

Desafio do dia

Você saberia encontrar o bug em Android?

Um trecho real, um bug escondido, uma tentativa por dia. Sem conta para testar.

Anthony Fillion-Maillet

Escrito por

Anthony Fillion-Maillet

Fundador da SharpSkill

Desenvolvedor fullstack há mais de 10 anos. Dirige a SharpSkill e responde por tudo o que é publicado aqui.

Atualizado em 22 de agosto de 2026

Tags

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

Compartilhar

Artigos relacionados