Quando a linha de execução de interface de um app Android é bloqueada por muito tempo, o erro "O app não está respondendo" (ANR) é acionado. Se o app estiver em primeiro plano, o sistema vai mostrar uma caixa de diálogo ao usuário, como na figura 1. A caixa de diálogo ANR dá ao usuário a oportunidade de forçar o fechamento do app.
ANRs são um problema porque fazem com que a linha de execução principal do app, que é responsável por atualizar a IU, não processe eventos de entrada do usuário ou não seja renderizada, causando frustração ao usuário. Para mais informações sobre a linha de execução principal do app, consulte Visão geral de processos e linhas de execução.
Um ANR é acionado para o app quando uma das seguintes condições ocorre:
- Tempo de entrega de entradas esgotado:se o app não respondeu a um evento de entrada (como pressionamento de tecla ou toque na tela) em até cinco segundos.
- Serviço executado:se um serviço declarado pelo app não consegue terminar a execução de
Service.onCreateeService.onStartCommand/Service.onBindem alguns segundos. Service.startForegroundnão chamado: Se o app usaContext.startForegroundServicepara iniciar um novo serviço em primeiro plano mas o serviço não chamastartForegrounddentro de cinco segundos.- Transmissão de intent: se uma
BroadcastReceivernão termina de ser executada dentro de um período definido. Se o app tem alguma atividade em primeiro plano, esse tempo limite é de cinco segundos. JobSchedulerinterações: se umJobServicenão retornar deJobService.onStartJobouJobService.onStopJobem alguns segundos, ou se um job iniciado pelo usuário começar e seu app não chamarJobService.setNotificationalguns segundos depois deJobService.onStartJobser chamado. Em apps destinados ao Android 13 e versões anteriores, os ANRs são silenciosos e não são informados ao app. Para apps direcionados ao Android 14 e versões mais recentes, os ANRs são explícitos e informados ao app.
Se o app estiver apresentando ANRs, use as orientações deste documento para diagnosticar e corrigir o problema.
Detectar o problema
Se você já publicou seu app, use o Android vitals para ver informações sobre os ANRs dele. É possível usar outras ferramentas para detectar ANRs, mas as ferramentas de terceiros não os informa em versões mais antigas do Android (Android 10 e anteriores), ao contrário do Android vitals.
Android vitals
O Android vitals pode ajudar a monitorar e melhorar a taxa de ANRs do seu app. Ele mede várias taxas de ANR:
- Taxa de ANR:é a porcentagem de usuários ativos por dia que tiveram qualquer tipo de ANR.
- Taxa de ANR percebido pelo usuário:é a porcentagem de usuários ativos por dia que perceberam pelo menos um ANR percebido pelo usuário. Atualmente, apenas ANRs do tipo
Input dispatching timed outsão considerados percebidos pelo usuário. - Taxa de ANRs múltiplos:é a porcentagem de usuários ativos por dia que tiveram pelo menos dois ANRs.
Um usuário ativo por dia é um usuário único que usa seu app em um único dia em um único dispositivo, possivelmente em várias sessões. Se o usuário utilizar o app em mais de um dispositivo em um único dia, cada dispositivo vai contribuir separadamente para o número de usuários ativos nesse dia.
A taxa de ANR percebido pelo usuário é uma das principais métricas, ou seja, ela afeta a possibilidade de descoberta do app no Google Play. Isso é importante porque os ANRs que ela conta sempre ocorrem quando o usuário está engajado com o app, o que causa mais interrupções.
O Google Play definiu dois limites de mau comportamento nessa métrica:
- Limite de mau comportamento geral:pelo menos 0, 47% dos usuários ativos por dia percebem um ANR percebido pelo usuário em todos os modelos de dispositivos.
- Limite de mau comportamento por dispositivo:pelo menos 8% dos usuários ativos por dia percebem um ANR percebido pelo usuário em um único modelo de dispositivo.
Se o app exceder o limite de mau comportamento geral, ele provavelmente será mostrado para menos pessoas em todos os dispositivos. Se o app excede o limite de mau comportamento por dispositivo em alguns modelos, ele provavelmente é mostrado para menos pessoas que usam esse tipo de dispositivo, e um aviso é mostrado na página "Detalhes do app".
O Android vitals pode enviar alertas pelo Play Console quando o app está apresentando muitos ANRs.
Para informações sobre como o Google Play coleta dados do Android vitals, consulte a Play Console documentação.
Diagnosticar ANRs
Há alguns padrões comuns que precisam ser observados ao diagnosticar ANRs:
- O app está fazendo operações lentas envolvendo E/S na linha de execução principal.
- O app está fazendo um cálculo longo na linha de execução principal.
- A linha de execução principal está fazendo uma chamada de vinculação síncrona para outro processo, e esse outro processo está demorando muito para retornar.
- A linha de execução principal está bloqueada e esperando um bloco sincronizado para uma operação longa que está acontecendo em outra linha de execução.
- A linha de execução principal está em um impasse com outra linha, seja em um processo ou em uma chamada de vinculação. A linha de execução principal não está apenas aguardando uma operação longa terminar, mas está em uma situação de impasse.
As técnicas a seguir podem ajudar a determinar a causa dos ANRs.
HealthStats
HealthStats fornece métricas sobre a integridade do app, coletando informações sobre tempo total de uso do usuário e do sistema, tempo de CPU, rede, estatísticas de rádio, tempo com a tela ativada e desativada e alarmes de ativação. Isso pode ajudar a medir o uso geral de CPU e o consumo de bateria.
Depuração
Debug ajuda a inspecionar aplicativos Android durante o desenvolvimento, fazendo uso de rastreamento e contagens de alocação para identificar instabilidade e pontos de atraso nos apps.
Também é possível usar Debug para receber contadores relacionados à memória nativa e ao tempo de execução, além de métricas de memória que podem ajudar a identificar o consumo de memória por um processo específico.
ApplicationExitInfo
ApplicationExitInfo está disponível no Android 11 (nível 30 da API) e versões mais recentes e fornece informações sobre o motivo do encerramento do app. Os motivos incluem ANRs, pouca memória, falhas no app, uso excessivo da CPU, interrupções do usuário, interrupções do sistema e mudanças na permissão de execução.
Modo restrito
Usar StrictMode ajuda a encontrar operações acidentais de E/S na linha de execução principal durante o desenvolvimento do app. Você pode usar StrictMode no nível do aplicativo ou da atividade.
Ativar caixas de diálogo ANR em segundo plano
O Android mostra caixas de diálogo ANR para apps que levam muito tempo para processar a mensagem de transmissão apenas se você ativar Mostrar todos os ANRs nas Opções do desenvolvedor do dispositivo. Por esse motivo, as caixas de diálogo ANR em segundo plano nem sempre são mostradas para o usuário, mesmo quando o app está apresentando problemas de desempenho.
Gargalos de recomposição
Use o Android Studio Profiler e o Layout Inspector para rastrear gargalos de recomposição. Para mais informações, consulte Jetpack Compose Performance.
Extrair um arquivo de rastreamento
O Android armazena informações de rastros quando passa por um ANR. Em versões mais antigas do SO, há um único arquivo /data/anr/traces.txt no dispositivo. Nas versões mais recentes do SO, há vários arquivos /data/anr/anr_*. Você pode acessar os rastros de ANR
em um dispositivo ou emulador usando o Android Debug Bridge (adb) como
raiz:
adb root
adb shell ls /data/anr
adb pull /data/anr/<filename>
Você pode capturar um relatório de bug de um dispositivo físico usando a opção de desenvolvedor "Criar relatório do problema" no dispositivo ou o comando adb bugreport na máquina de desenvolvimento. Para mais informações, consulte
Capturar e ler relatórios de bugs.
Corrigir os problemas
Depois de identificar o problema, você pode usar as dicas desta seção para corrigir problemas encontrados com frequência.
Código lento na linha de execução principal
Identifique os lugares no código em que a linha de execução principal do app está ocupada por mais de cinco segundos. Procure os casos de uso suspeitos no app e tente reproduzir o ANR.
Um problema comum é uma tarefa de longa duração diretamente em um elemento combinável:
@Composable
fun BadList(rawStrings: List<String>) {
// Math or sorting inside the composable runs on EVERY recomposition pass!
val heavilyProcessedList = rawStrings
.filter { it.isNotBlank() }
.map { it.uppercase().reversed() }
.map { it.computationallyHeavyFunction() }
.sortedBy { it.length }
LazyColumn { items(sortedList) { Text(it) } }
}
// Modern Compose-first fix
@Composable
fun GoodList(viewModel: MyViewModel = viewModel()) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
// UI simply renders state; no heavy processing allowed here
LazyColumn { items(uiState.sortedData) { Text(it) } }
}
E/S na linha de execução principal
A execução de operações de E/S na linha de execução principal é uma causa comum de operações lentas, o que pode causar ANRs. No Compose, os desenvolvedores costumam acionar acidentalmente leituras de disco (como SharedPreferences ou chamadas de banco de dados) ao tentar derivar o estado inicial.
Execute operações de E/S de longa duração fora da camada de interface. Use
withContext(Dispatchers.IO) em uma ViewModel ou, ainda melhor, use um
Repository na camada de dados.
Impasses
Um impasse ocorre quando uma linha de execução entra em um estado de espera porque um recurso necessário é retido por outra linha, que também está aguardando um recurso retido pela primeira. Se a linha de execução principal do app estiver nessa situação, é provável que ANRs aconteçam.
Os impasses são um fenômeno bem estudado na ciência da computação e existem algoritmos de prevenção que você pode usar para os evitar.
Para mais informações, consulte Impasse e Algoritmos de prevenção de impasse na Wikipedia.
Ao usar o Kotlin e o Compose, você pode substituir bloqueios primitivos por
mutexes de corrotina não bloqueadores (Mutex.withLock) para evitar o bloqueio de linhas de execução
suspendendo o contexto de execução em vez de congelar a linha de execução de
interface. Exemplo:
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
// Modern non-blocking concurrency state architecture
class SecureDataRepository {
private val mutex = Mutex()
suspend fun safeUIAccess() {
// If locked, the main thread suspends seamlessly, preventing an ANR
mutex.withLock {
performSafeOperation()
}
}
}
Broadcast receivers lentos
Os apps podem responder a mensagens de transmissão, como ativar ou desativar o modo avião ou mudar o status de conectividade usando broadcast receivers. Um ANR ocorre quando um app demora muito para processar a mensagem de transmissão.
Um ANR ocorre nestes casos:
- Após um período considerável, um broadcast receiver ainda não concluiu a execução do método
onReceive. - Um broadcast receiver chama
goAsynce falha ao chamarfinishno objetoPendingResult.
O app só pode executar operações curtas no onReceive método
de um BroadcastReceiver. No entanto, se o app exigir processamento mais complexo
como resultado de uma mensagem de transmissão, você vai precisar adiar a tarefa para uma
ViewModel (aproveitando o poder das corrotinas, escopos e agentes do Kotlin)
se a tarefa levar alguns segundos no máximo, qualquer tipo de detentor de estado,
ou para WorkManager para tarefas que devem levar mais de alguns segundos.
GameActivity
A biblioteca GameActivity reduziu os ANRs em estudos de caso de
jogos e apps escritos em C ou C++. Se você substituir a atividade nativa existente por GameActivity, poderá reduzir o bloqueio de linhas de execução de interface e impedir que alguns
ANRs ocorram.
Para mais informações sobre ANRs, consulte Como manter seu app responsivo. Para mais informações sobre linhas de execução, consulte Melhor desempenho com linhas de execução.
Outros recursos
Visualizar conteúdo
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado
- Ativações excessivas