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 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 dos processos e das 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 um
BroadcastReceivernão termina de ser executado dentro de um período definido. Se o app tem alguma atividade em primeiro plano, esse tempo limite é de cinco segundos. - Interações do
JobScheduler: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.setNotificationem alguns 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.
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 no seu 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 de um aplicativo ao
capturar o tempo total de uso do usuário e do sistema, tempo de CPU, rede, estatísticas de rádio, tempo com a tela
ativada/desativada e alarmes de ativação. Isso pode ajudar você a medir o uso geral da CPU e o consumo de bateria.
Depuração
O Debug ajuda a inspecionar aplicativos Android durante o desenvolvimento,
incluindo rastreamento e contagens de alocação para identificar instabilidade e 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) ou
mais recente e fornece informações sobre o motivo do encerramento do app. Isso inclui 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á com problemas de desempenho.
Gargalos de recomposição
Use o Profiler do Android Studio e o Layout Inspector para rastrear gargalos de recomposição. Para mais informações, consulte Performance do Jetpack Compose.
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 muitas vezes
acionam 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 longe da camada de interface. Use
withContext(Dispatchers.IO) em um ViewModel ou, melhor ainda, 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 Wikipédia.
Ao usar Kotlin e Compose, você pode substituir bloqueios primitivos por
Mutexes de corrotina sem bloqueio (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
da 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 não chamafinishno objetoPendingResult.
O app só pode executar operações curtas no método onReceive
de um BroadcastReceiver. No entanto, se o app exigir um processamento mais complexo
como resultado de uma mensagem de transmissão, adie a tarefa para um
ViewModel (aproveitando o poder das corrotinas, escopos e distribuidores 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
atual 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 Manter seu app responsivo. Para mais informações sobre linhas de execução, consulte Melhor performance usando linhas de execução.
Outros recursos
Visualiza conteúdo
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado
- Ativações excessivas