Cuando se bloquea durante demasiado tiempo el subproceso de IU de una app para Android, se activa un error del tipo "Aplicación no responde" (ANR). Si la app está en primer plano, el usuario podrá ver un diálogo del sistema, como se observa en la Figura 1. Este diálogo de error de ANR le permite forzar el cierre de la app.
Los errores de ANR representan un problema porque el subproceso principal de la app, que se encarga de actualizar la IU, no puede procesar eventos de entrada del usuario ni obtener datos, lo que le genera frustración al usuario. Para obtener más información sobre el subproceso principal de la app, consulta Descripción general de procesos y subprocesos.
Cuando se produce una de las siguientes condiciones, se activa un error de ANR en tu app:
- Tiempo de espera para el ingreso de datos agotado: La app no respondió a un evento de entrada (como presionar una tecla o tocar la pantalla) en 5 segundos
- Servicio en ejecución: La app declaró un servicio que no puede terminar de ejecutar
Service.onCreateyService.onStartCommand/Service.onBinden unos segundos. Service.startForegroundno se llama: Si tu app usaContext.startForegroundServicepara iniciar un servicio nuevo en primer plano, pero el servicio no llama astartForegrounden 5 segundos.- Transmisión del intent: Cuando un objeto
BroadcastReceiverno terminó de ejecutarse dentro de un período establecido. Si la app tiene alguna actividad en primer plano, el tiempo de espera es de 5 segundos. JobSchedulerinteracciones: Si un objetoJobServiceno devuelve un valor deJobService.onStartJoboJobService.onStopJoben unos segundos, o si se inicia un trabajo iniciado por el usuario y tu app no llama aJobService.setNotificationunos segundos después de que se llama aJobService.onStartJob. En el caso de las apps orientadas a Android 13 y versiones anteriores, los errores de ANR se silencian y no se informan a la app. En el caso de las apps orientadas a Android 14 y versiones posteriores, estos errores son explícitos y se informan a la app.
Si tu app presenta errores de ANR, puedes seguir las indicaciones que se incluyen en este documento para diagnosticar el problema y corregirlo.
Cómo detectar el problema
Si ya publicaste tu app, puedes usar Android vitals para ver información de los ANR de tu app. Puedes usar otras herramientas para detectar ANR en el campo, pero ten en cuenta que, a diferencia de Android vitals, las herramientas de terceros no pueden informar si existen ANR en Android 10 y versiones anteriores.
Android vitals
Android vitals puede ayudarte a supervisar y mejorar la tasa de ANR de tu app. Android vitals mide varias tasas de ANR:
- Tasa de ANR: Es el porcentaje de usuarios activos por día que experimentaron algún tipo de ANR.
- Tasa de errores de ANR percibidos por el usuario: Es el porcentaje de usuarios activos por día que experimentaron al menos un Error de ANR percibido por el usuario. Actualmente, solo los ANR de tipo
Input dispatching timed outse consideran percibidos por el usuario. - Tasa de ANR múltiples: Es el porcentaje de usuarios activos por día que experimentaron al menos dos ANR.
Un usuario activo por día es un usuario único que usa tu app en un solo día en un solo dispositivo, posiblemente en varias sesiones. Si un usuario usa tu app en más de un dispositivo en un solo día, cada dispositivo contribuirá a la cantidad de usuarios activos de ese día.
La tasa de errores de ANR percibidos por el usuario es una métrica esencial, lo que significa que afecta la visibilidad de tu app en Google Play. Es importante porque los ANR que cuenta ocurren siempre cuando el usuario interactúa con la app y, por lo tanto, causan la mayor cantidad de interrupciones.
Play definió dos umbrales de comportamiento inadecuado en esta métrica:
- Umbral de comportamiento inadecuado general: Al menos el 0.47% de los usuarios activos por día experimentan un Error de ANR percibido por el usuario en todos los modelos de dispositivos.
- Umbral de comportamiento inadecuado por dispositivo: Al menos el 8% de los usuarios por día experimentan un Error de ANR percibido por el usuario en un solo modelo de dispositivo.
Si tu app supera el umbral general de comportamiento inadecuado, es probable que sea menos detectable en todos los dispositivos. Si la app supera el umbral de comportamiento inadecuado en algunos dispositivos, es probable que sea menos visible en estos y que se muestre una advertencia en la ficha de Play Store.
Android vitals puede enviarte alertas a través de Play Console cuando tu app presenta una cantidad excesiva de ANR.
Si deseas obtener información sobre cómo Google Play recopila datos de Android vitals, consulta la Play Console documentación.
Diagnostica ANR
Cuando diagnosticas los errores de ANR, debes tener en cuenta algunos patrones comunes:
- La app realiza operaciones lentas de E/S en el subproceso principal.
- La app realiza un cálculo largo en el subproceso principal.
- El subproceso principal realiza una llamada síncrona de Binder a otro proceso, y dicho proceso tarda mucho tiempo en responder.
- El subproceso principal está bloqueado a la espera de un bloque sincronizado para una operación larga que se produce en otro subproceso.
- El subproceso principal se interbloqueó con otro subproceso, ya sea en tu proceso o mediante una llamada a Binder. El subproceso principal no solo está a la espera de que termine una operación larga, sino que se interbloqueó en una situación de interbloqueo.
Las siguientes técnicas pueden ayudarte a determinar la causa de los ANR.
HealthStats
HealthStats proporciona métricas sobre el estado de una aplicación, ya que captura el tiempo total del usuario y del sistema, el tiempo de CPU, la red, las estadísticas de radio, el tiempo de encendido y apagado de la pantalla y las alarmas de activación. Esto puede ayudarte a medir el uso general de la CPU y el agotamiento de la batería.
Depurar
Debug ayuda a inspeccionar aplicaciones para Android durante el desarrollo, incluidos los registros de seguimiento y asignación, para identificar bloqueos y retrasos en las apps.
También puedes usar Debug para obtener contadores de tiempo de ejecución y memoria nativa, y métricas de memoria que pueden ayudarte a identificar el espacio en memoria de un proceso en particular.
ApplicationExitInfo
ApplicationExitInfo está disponible en Android 11 (nivel de API 30) o versiones posteriores, y proporciona información sobre el motivo de la salida de la aplicación. Esto incluye errores de ANR, memoria insuficiente, fallas de apps, uso excesivo de CPU, interrupciones del usuario, interrupciones del sistema o cambios en los permisos de tiempo de ejecución.
Modo estricto
El uso de StrictMode te ayudará a encontrar las operaciones de E/S con accidentes en el subproceso principal
mientras desarrollas tu app. Puedes usar StrictMode en el
nivel de la aplicación o la actividad.
Habilita diálogos de errores de ANR en segundo plano
Android muestra los diálogos de errores de ANR cuando las app tardan demasiado en procesar el mensaje de emisión solo si está habilitada la opción Mostrar todos los errores sin respuesta en las Opciones para desarrolladores del dispositivo. Por esta razón, el usuario no siempre recibirá los diálogos de errores de ANR en segundo plano, incluso cuando la app presente problemas de rendimiento.
Cuellos de botella de recomposición
Usa el Generador de perfiles de Android Studio y el Inspector de diseño para detectar cuellos de botella de recomposición. Para obtener más información, consulta Rendimiento de Jetpack Compose.
Cómo extraer un archivo de registro
Android almacena la información de registro cuando presenta un error de ANR. En las versiones anteriores de SO, hay un único archivo /data/anr/traces.txt en el dispositivo. En las versiones más recientes de SO, hay varios archivos /data/anr/anr_*. Puedes acceder a los registros de errores de ANR
desde un dispositivo o emulador. Para ello, utiliza Android Debug Bridge (adb) como
raíz:
adb root
adb shell ls /data/anr
adb pull /data/anr/<filename>
Puedes capturar un informe de errores desde un dispositivo físico mediante la opción para desarrolladores Iniciar informe de errores en el dispositivo o con el comando adb bugreport en tu máquina de desarrollo. Para obtener más información, consulta
Cómo capturar y leer informes de errores.
Cómo corregir problemas
Una vez que hayas identificado el problema, puedes usar las sugerencias incluidas en esta sección para corregir problemas habituales.
Código lento en el subproceso principal
Identifica las partes de tu código donde el subproceso principal de la app está ocupado durante más de 5 segundos. Busca los casos de uso sospechosos en tu app e intenta reproducir el error de ANR.
Un problema habitual es una tarea de larga duración directamente en un elemento componible:
@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 en el subproceso principal
Cuando se ejecutan operaciones de E/S en el subproceso principal, las operaciones se ralentizan y se pueden producir errores de ANR. En Compose, los desarrolladores suelen activar accidentalmente lecturas de disco (como SharedPreferences o llamadas a la base de datos) mientras intentan derivar el estado inicial.
Ejecuta operaciones de E/S de larga duración fuera de la capa de IU. Usa
withContext(Dispatchers.IO) en un ViewModel o, mejor aún, usa un
Repository en la capa de datos.
Interbloqueos
Se produce un interbloqueo cuando un subproceso entra en estado de espera porque otro subproceso retiene un recurso requerido, y este otro subproceso también está a la espera del recurso que retiene el primer subproceso. Si esta situación ocurre en el subproceso principal de la app, es probable que se produzca un error de ANR.
Los interbloqueos son un fenómeno muy estudiado en la informática, y existen algoritmos de prevención de interbloqueos que puedes aplicar para evitarlos.
Para obtener más información, consulta las entradas sobre interbloqueos y algoritmos de prevención de interbloqueos en Wikipedia.
Cuando usas Kotlin y Compose, puedes sustituir los bloqueos primitivos por
Mutexes de corrutina sin bloqueo (Mutex.withLock) para evitar el bloqueo de subprocesos
suspendiendo el contexto de ejecución en lugar de congelar el subproceso de IU. Por ejemplo:
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()
}
}
}
Receptores de emisión lenta
A través de los receptores de emisión, las apps pueden responder a los mensajes de emisión, como habilitar o inhabilitar el modo de avión o un cambio en el estado de conectividad. Los errores de ANR se producen cuando una app tarda demasiado en procesar el mensaje de emisión.
Los errores de ANR se producen en los siguientes casos:
- Cuando un receptor de transmisiones no terminó de ejecutar su
onReceivemétodo en un lapso considerable. - Cuando un receptor de transmisiones llama a
goAsyncy no llama afinishen el objetoPendingResult.
Tu app solo debe realizar operaciones cortas en el onReceive método
de un BroadcastReceiver. Sin embargo, si su aplicación requiere un procesamiento más complejo
como resultado de un mensaje de emisión, debe diferir la tarea a un
ViewModel (aprovechando la potencia de las corrutinas, los alcances y los despachadores de Kotlin)
si se espera que la tarea tarde unos segundos como máximo, cualquier tipo de titular de estado,
o a WorkManager para las tareas que se espera que tarden más de unos segundos.
GameActivity
La biblioteca de GameActivity redujo los errores de ANR en los casos de éxito de
juegos y apps escritos en C o C++. Si reemplazas tu actividad nativa existente por GameActivity, puedes reducir el bloqueo del subproceso de IU y evitar que se produzcan algunos
errores de ANR.
Para obtener más información sobre los errores de ANR, consulta Cómo mantener la capacidad de respuesta de tu app. Si deseas obtener más información sobre los subprocesos, consulta Mejor rendimiento a través de subprocesos.
Recursos adicionales
Contenido de Views
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- Demasiadas activaciones