Mantén la capacidad de respuesta de tu app

Figura 1: Diálogo de ANR que se le muestra al usuario

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() y onResume(). 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 con Context.registerReceiver. Para obtener más información, consulta la sección Errores de ANR en BroadcastReceiver.

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.