Os processos em segundo plano podem consumir muita memória e bateria. Por exemplo, uma transmissão implícita pode iniciar muitos processos em segundo plano que foram registrados para ouvi-la, mesmo que esses processos não tenham tanta utilidade. Isso pode ter um impacto significativo no desempenho do dispositivo e na experiência do usuário.
Para evitar restrições do sistema, use a API certa para sua tarefa em segundo plano. A documentação Visão geral das tarefas em segundo plano ajuda você a escolher a API certa para suas necessidades.
Restrições iniciadas pelo usuário
Se um app apresenta alguns dos maus comportamentos descritos no Android vitals, o sistema solicita que o usuário restrinja o acesso desse app aos recursos do sistema.
Se o sistema perceber que um app está consumindo recursos em excesso, ele vai notificar o usuário e dará a opção de restringir as ações do app. Os comportamentos que podem acionar o aviso incluem:
- Wake locks em excesso: um wake lock parcial mantido por uma hora quando a tela está desativada
- Serviços em segundo plano em excesso: o app segmenta níveis de API inferiores a 26 e há excesso de serviços em segundo plano.
As restrições precisas impostas são determinadas pelo fabricante do dispositivo. Por exemplo, em versões do AOSP, os apps restritos não podem executar tarefas, acionar alarmes nem usar a rede, exceto quando o app está no primeiro plano.
Restrições para o recebimento de transmissões de atividade de rede
Os apps não recebem CONNECTIVITY_ACTION transmissões quando se registram para
recebê-las no manifesto. Processos que dependem dessa transmissão
não serão iniciados. Isso pode representar um problema para apps que querem ouvir mudanças de rede ou realizar atividades de rede em massa quando o dispositivo se conecta a uma rede ilimitada. Várias soluções para contornar essa restrição já existem no framework do Android, mas escolher o caminho certo depende do que você quer que o app faça.
Agendar trabalho em conexões ilimitadas
Ao criar um WorkRequest, adicione uma Constraint NetworkType.UNMETERED.
fun scheduleWork(context: Context) {
val workManager = WorkManager.getInstance(context)
val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.build()
)
.build()
workManager.enqueue(workRequest)
}
Quando as condições para o trabalho forem atendidas, o app vai receber um callback para executar
o doWork() método na classe Worker especificada.
Monitorar a conectividade de rede enquanto o app está em execução
Os apps em execução ainda podem detectar CONNECTIVITY_CHANGE com um
BroadcastReceiverregistrado. No entanto, a ConnectivityManager API
fornece um método mais robusto para solicitar um callback somente quando as condições de rede
especificadas são atendidas.
NetworkRequest objetos definem os parâmetros do callback de rede em
termos de NetworkCapabilities. Você cria NetworkRequest objetos
com a classe NetworkRequest.Builder. registerNetworkCallback
em seguida, transmite o objeto NetworkRequest para o sistema. Quando as condições da rede
são atendidas, o app recebe um callback para executar o
onAvailable() método definido na classe
ConnectivityManager.NetworkCallback.
O app continua recebendo callbacks até o app sair ou chamar unregisterNetworkCallback().
Restrições para o recebimento de transmissões de imagens e vídeos
Os apps não podem enviar nem receber transmissões ACTION_NEW_PICTURE ou ACTION_NEW_VIDEO. Essa restrição ajuda a reduzir os impactos no desempenho e na experiência do usuário quando vários apps precisam ser ativados para processar uma nova imagem ou vídeo.
Determinar quais autoridades de conteúdo acionaram o trabalho
WorkerParameters permite que o app receba informações úteis sobre quais autoridades de conteúdo e URIs acionaram o trabalho:
List<Uri> getTriggeredContentUris()
Retorna uma lista de URIs que acionaram o trabalho. Essa lista fica vazia se nenhum URI tiver acionado o trabalho (por exemplo, se ele foi acionado devido a um prazo ou outro motivo) ou se o número de URIs alterados for maior que 50.
List<String> getTriggeredContentAuthorities()
Retorna uma lista de strings de autoridades de conteúdo que acionaram o trabalho. Se a lista retornada não estiver vazia, use getTriggeredContentUris() para recuperar os detalhes sobre quais URIs foram modificados.
O exemplo de código abaixo modifica o CoroutineWorker.doWork() método
e registra as autoridades de conteúdo e os URIs que acionaram o job.
class MyWorker(
appContext: Context,
params: WorkerParameters
): CoroutineWorker(appContext, params)
override suspend fun doWork(): Result {
StringBuilder().apply {
append("Media content has changed:\n")
params.triggeredContentAuthorities
.takeIf { it.isNotEmpty() }
?.let { authorities ->
append("Authorities: ${authorities.joinToString(", ")}\n")
append(params.triggeredContentUris.joinToString("\n"))
} ?: append("(No content)")
Log.i(TAG, toString())
}
return Result.success()
}
}
Testar o app em restrições do sistema
A otimização dos seus apps para serem executados em dispositivos com pouca memória ou em condições de pouca memória pode melhorar o desempenho e a experiência do usuário. A remoção de dependências em serviços em segundo plano e de broadcast receivers implícitos registrados pelo manifesto pode ajudar o app a funcionar melhor nesses dispositivos. Recomendamos que você otimize seu app para ser executado totalmente sem esses processos em segundo plano.
Alguns outros comandos do Android Debug Bridge (ADB) podem ajudar a testar o comportamento do app quando esses processos em segundo plano estão desativados:
Para simular condições em que transmissões implícitas e serviços em segundo plano estão indisponíveis, digite o comando abaixo:
$ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignorePara reativar transmissões implícitas e serviços em segundo plano, digite o comando abaixo:
$ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow
Otimizar ainda mais seu app
Para outras boas maneiras de otimizar o comportamento das tarefas em segundo plano, consulte a documentação Otimizar o uso da bateria para APIs de agendamento de tarefas.