Segundo plano no Android: WorkManager ou serviço?
Segundo plano no Android em 2026: quando usar WorkManager, setForeground, UIDT ou serviço em primeiro plano, com as regras do Android 12, 14 e 15.
No Android atual não existe serviço que roda para sempre em silêncio. Trabalho que pode esperar vai para o WorkManager; trabalho contínuo que a pessoa acompanha vira serviço em primeiro plano, com notificação e tipo declarado; e transferências grandes pedidas pela pessoa têm, desde o Android 14, uma API própria. Este guia ajuda a escolher entre as opções com as regras em vigor em outubro de 2026, conferidas na documentação oficial do Android.
Se você já escolheu o WorkManager e o problema é uma tarefa longa que para no meio, como o envio de centenas de fotos, o passo a passo de retomada está em upload longo no Android: WorkManager que retoma.
Por que o serviço antigo para de rodar
O Service com START_STICKY que aparece em tutorial antigo era desenhado para um sistema que não existe mais. As regras foram apertando versão a versão:
- Android 6: Doze e App Standby. Com o aparelho parado e a tela apagada, rede, alarmes e jobs ficam agrupados em janelas de manutenção (Doze e App Standby).
- Android 8: limites de execução em segundo plano. Pouco depois de o app sair da tela, o sistema para os serviços que não estão em primeiro plano.
- Android 12: apps que miram a API 31 ou superior não podem iniciar serviço em primeiro plano enquanto estão em segundo plano, salvo exceções, e a tentativa lança
ForegroundServiceStartNotAllowedException. - Android 14: todo serviço em primeiro plano precisa declarar um tipo no manifesto (localização, mídia, sincronização de dados e outros) e pedir a permissão correspondente.
- Android 15: serviços dos tipos
dataSyncemediaProcessingpodem rodar no total 6 horas a cada 24 horas. No limite, o sistema chamaonTimeout()e o serviço tem alguns segundos para chamarstopSelf().
Some a isso os gerenciadores de bateria de alguns fabricantes, mais agressivos que o Android padrão, e a possibilidade de o processo morrer por falta de memória a qualquer momento. O desenho que funciona assume que o processo pode sumir e guarda o estado em disco.
Escolha pela pergunta, não pela API
A documentação de tarefas em segundo plano separa os casos pelo que o trabalho precisa. Resumido:

Pode esperar: WorkManager
Sincronizar pedidos, mandar log, baixar catálogo. O WorkManager guarda o pedido em banco, sobrevive a reinício do aparelho e respeita restrições como rede conectada. Um worker comum tem limite de 10 minutos por execução.
Longo e importante para a pessoa: WorkManager com setForeground
Se o trabalho precisa passar de 10 minutos, o CoroutineWorker chama setForeground() e o WorkManager sobe um serviço em primeiro plano por você, com notificação. A página de workers de longa duração diz que, mirando o Android 14 ou superior, você precisa declarar o tipo de serviço para todo worker desse tipo. Para envio de arquivos, o tipo é dataSync, sujeito ao limite de 6 horas do Android 15.
Transferência grande pedida pela pessoa: UIDT
O job de transferência iniciado pelo usuário (UIDT) chegou no Android 14. É um job do JobScheduler criado com setUserInitiated(true), exige a permissão RUN_USER_INITIATED_JOBS e uma notificação, começa na hora e pode rodar por bastante tempo se o sistema permitir. Precisa ser agendado com o app visível para a pessoa.
Contínuo e visível: serviço em primeiro plano
Registrar a rota de um vendedor durante o expediente, tocar música, manter uma chamada. A pessoa sabe que está rodando, a notificação fica na barra e o tipo declarado (location, mediaPlayback, phoneCall) casa com o que o serviço faz.
Horário ou servidor: alarme ou push
Lembrete numa hora marcada é alarme ou notificação agendada. Se a informação nasce no servidor, o caminho é push, não um serviço consultando a API em loop. A diferença está em notificação local não é push.
O mesmo app com duas necessidades
Um app de vendas externas precisa sincronizar pedidos feitos sem sinal (pode esperar) e registrar a rota durante o expediente (contínuo e visível). São duas APIs diferentes.
A sincronização vira um trabalho único, com restrição de rede, enfileirado cada vez que um pedido é salvo, com a versão estável da biblioteca na data deste post (androidx.work:work-runtime-ktx:2.12.0, segundo a página de versões do WorkManager):
class SincronizarPedidosWorker(
contexto: Context,
params: WorkerParameters
) : CoroutineWorker(contexto, params) {
override suspend fun doWork(): Result {
val repo = PedidosRepository(applicationContext)
return try {
for (pedido in repo.pendentes()) { // lidos do Room, não da memória
repo.enviar(pedido) // o servidor ignora pedido repetido pelo id
repo.marcarEnviado(pedido.id)
}
Result.success()
} catch (e: IOException) {
if (runAttemptCount < 5) Result.retry() else Result.failure()
}
}
}
fun agendarSincronizacao(contexto: Context) {
val pedido = OneTimeWorkRequestBuilder<SincronizarPedidosWorker>()
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 30, TimeUnit.SECONDS)
.build()
WorkManager.getInstance(contexto).enqueueUniqueWork(
"sincronizar-pedidos",
ExistingWorkPolicy.KEEP, // já tem um na fila? não duplica
pedido
)
}
A rota é um serviço em primeiro plano do tipo location, iniciado quando a pessoa toca em "Começar expediente", com o app aberto:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<service
android:name=".RotaService"
android:foregroundServiceType="location"
android:exported="false" />
Os pontos da rota vão para o banco local a cada leitura. Se o processo morrer, o que já foi gravado não se perde, e o serviço reabre do último ponto. Onde cada tipo de dado deve morar no aparelho está em onde o app Android guarda os dados.
Erros que a loja e o sistema cobram
- Tipo errado para esconder trabalho. O Google Play pede que cada tipo de serviço em primeiro plano seja declarado e justificado no Play Console. Um
locationnum serviço que só sincroniza não se sustenta na revisão, e ainda exige a permissão de localização em tempo de execução. - Iniciar o serviço a partir de segundo plano. Desde o Android 12 isso lança exceção fora dos casos permitidos. Agende um worker e deixe o WorkManager decidir.
- Ignorar o
onTimeout(). No Android 15, um serviçodataSyncque não chamastopSelf()a tempo gera uma exceção interna e encerra o app. - Confiar no teste com cabo. Com o aparelho carregando e a tela acesa, Doze não entra. Teste com os comandos
adbda página de Doze, num aparelho de verdade, como em celular Android para depurar.
O código deste post segue as APIs da documentação citada, mas não foi compilado aqui: o ambiente usado para escrever não tem o SDK do Android. Confira as versões no seu build.gradle antes de copiar.