En este documento, se describe la manera en que el sistema Android determina si una app no responde y se muestra cómo mantener la capacidad de respuesta de tu app.
Sin importar qué tan bien escrito esté el código, es posible que tu app se vea lenta, se bloquee o tarde demasiado tiempo en procesar los datos de entrada. Si tu app está en primer plano y no responde, el usuario verá un diálogo de Aplicación no responde (ANR), como se muestra en la figura 1. El diálogo de ANR permite que el usuario fuerce el cierre de la app. Si la app no está en primer plano, se detiene en silencio. Es fundamental diseñar la capacidad de respuesta de tu app para minimizar los diálogos de ANR.
Activadores de ANR
Por lo general, el sistema muestra un error de ANR si una app no puede responder a la entrada del usuario en el subproceso principal (también conocido como subproceso de IU), lo que impide que el sistema procese estos eventos de entrada.
Por ejemplo, puede producirse un error de ANR si una app realiza una operación de bloqueo de E/S, como el acceso a la red, en el subproceso de IU. Otro ejemplo es cuando una app tarda demasiado creando una estructura en memoria elaborada o calculando el siguiente movimiento en un juego en el subproceso de IU.
En Android, los servicios del sistema ActivityManager
y WindowManager
supervisan la capacidad de respuesta de las apps. Android muestra el diálogo de ANR de una app cuando detecta una de las siguientes condiciones:
- No se produce una respuesta a un evento de entrada (como presionar la pantalla o usar las teclas) después de 5 segundos.
- Un
BroadcastReceiver
no termina de ejecutarse en un plazo de 10 a 20 segundos para intents en primer plano. Para obtener más información, consulta Tiempo de espera del receptor de emisión.
Cómo evitar los errores de ANR
Las siguientes son sugerencias generales para evitar los errores de ANR. Si quieres obtener más información para diagnosticar y depurar diferentes tipos de errores de ANR, consulta las otras páginas de esta sección.
Mantén el subproceso principal desbloqueado en todo momento y usa los subprocesos de forma estratégica.
No realices operaciones de bloqueo ni de larga duración en el subproceso principal de la app. En su lugar, crea un subproceso de trabajo y haz la mayor parte del trabajo allí.
Intenta minimizar cualquier contención de bloqueo entre el subproceso principal y otros subprocesos.
Minimiza cualquier trabajo no relacionado con la IU en el subproceso principal, como cuando se manejan transmisiones o se ejecutan servicios. Cualquier método que se ejecute en el subproceso de IU debe realizar el menor trabajo posible en ese subproceso. En particular, las actividades deben hacer lo mínimo posible para configurarse en métodos clave de ciclo de vida, como
onCreate()
yonResume()
. Consulta Descripción general del trabajo en segundo plano para obtener más información sobre las soluciones disponibles para programar el trabajo en un subproceso en segundo plano y comunicarse con la IU.Ten cuidado cuando compartas grupos de subprocesos entre componentes. No uses los mismos subprocesos para operaciones que podrían ser de bloqueo prolongado y tareas urgentes, como la recepción de transmisiones.
Procura que el inicio de la app sea rápido. Minimiza las operaciones lentas o de bloqueo en el código de inicio de la app, como los métodos que se ejecutan durante la inicialización de Dagger.
Si usas
BroadcastReceiver
, considera ejecutar receptores de emisión en un subproceso que no sea el principal conContext.registerReceiver
. Para obtener más información, consulta la sección Errores de ANR en BroadcastReceiver.- Si usas
goAsync()
, asegúrate de que se llame aPendingResult.finish
rápidamente antes de que se agote el tiempo de espera del error de ANR.
- Si usas
Errores de ANR en BroadcastReceiver
El tiempo de ejecución de BroadcastReceiver
está limitado porque los receptores de emisión están destinados a realizar cantidades pequeñas y discretas de trabajo en segundo plano, como guardar una opción de configuración o registrar una Notification
. Al igual que con otros métodos llamados en el subproceso de IU, las apps deben evitar las operaciones o los cálculos de larga duración en un receptor de emisión. En lugar de realizar tareas de larga duración a través del subproceso de IU, ejecútalas en segundo plano para una ejecución posterior. Consulta Descripción general del trabajo en segundo plano para obtener más información sobre posibles soluciones.
Otro problema común se presenta cuando los objetos BroadcastReceiver
se ejecutan con demasiada frecuencia. La ejecución frecuente en segundo plano puede reducir la cantidad de memoria disponible para otras apps. Para obtener más información sobre cómo habilitar o inhabilitar objetos BroadcastReceiver
de manera eficiente, consulta la Descripción general de las transmisiones.
Cómo reforzar la capacidad de respuesta
Por lo general, es de 100 a 200 ms el umbral más allá del cual los usuarios perciben la lentitud en una app. A continuación, se incluyen sugerencias adicionales para que tu app resulte responsiva:
Si tu app realiza tareas en segundo plano como respuesta a una entrada del usuario, muestra el progreso, por ejemplo, con un elemento
ProgressBar
en la IU.En el caso de los juegos, realiza los cálculos de los movimientos en un subproceso de trabajo.
Si tu app tiene una fase de configuración inicial que consume mucho tiempo, considera mostrar una pantalla de presentación o renderizar la vista principal lo más rápido posible. Indica que la carga está en curso y completa la información de forma asíncrona. En cualquier caso, recomendamos indicar de alguna manera el progreso para que el usuario no perciba que la app se bloqueó.
Usa herramientas de rendimiento como Perfetto y el Generador de perfiles de CPU para determinar cuellos de botella en la capacidad de respuesta de tu app.