Programação Por Equipe DevBras

Capa do artigo: Segundo plano no Android: WorkManager ou serviço?

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 dataSync e mediaProcessing podem rodar no total 6 horas a cada 24 horas. No limite, o sistema chama onTimeout() e o serviço tem alguns segundos para chamar stopSelf().

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 location num 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ço dataSync que não chama stopSelf() 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 adb da 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.

Avalie este artigo

Referência: https://pt.stackoverflow.com/questions/137071/como-fazer-aplica%C3%A7%C3%A3o-rodando-em-segundo-plano-o-tempo-todo