Orientación sobre el cambio de comportamiento de MessageQueue

A partir de Android 17, las apps que se segmentan para Android 17 o versiones posteriores reciben una nueva implementación sin bloqueo de android.os.MessageQueue. La nueva implementación mejora el rendimiento y reduce los fotogramas perdidos, pero puede dañar los clientes que reflejan los campos y métodos privados de MessageQueue.

Android 17 introduce una revisión importante en el funcionamiento de Looper y Handler, ya que se reescribió la clase MessageQueue subyacente. Desde el primer lanzamiento del sistema operativo Android, MessageQueue se basó en un solo bloqueo para administrar la cola de tareas del subproceso principal. Este diseño a menudo causaba contención de bloqueo: un subproceso en segundo plano podía bloquear el subproceso principal, lo que provocaba fotogramas descartados y atascos en la IU.

Mitiga el impacto

Es posible que este cambio afecte a tu app si esta o sus dependencias se basan en la reflexión en tiempo de ejecución para inspeccionar MessageQueue. Evita usar la reflexión del tiempo de ejecución para inspeccionar MessageQueue.

Con la implementación heredada, los desarrolladores a veces accedían a campos privados, como MessageQueue.mMessages, para inspeccionar los mensajes pendientes. Con la nueva implementación sin bloqueos, las estructuras de datos internas cambiaron por completo. Para mantener la compatibilidad binaria, Android 17 conserva el campo mMessages, pero, en la nueva implementación, este campo es siempre nulo, independientemente de si hay mensajes en la cola.

Además, si usas algunas bibliotecas de prueba populares, deberás actualizarlas para que sean compatibles con la nueva implementación de MessageQueue.

Espresso

Espresso se usa comúnmente para las pruebas de IU. La biblioteca de Espresso necesita saber cuándo el subproceso principal está inactivo para realizar aserciones correctamente sobre el estado de la IU. Las versiones anteriores de Espresso se basaban en técnicas de reflexión que ya no son compatibles con MessageQueue sin bloqueo.

Acción

Actualiza a Espresso 3.7.0 o una versión posterior. Esta versión usa la API de TestLooperManager, en particular, las nuevas APIs que introdujo Android 16, para interactuar de forma segura con Looper sin depender de los detalles de implementación internos.

Robolectric

Del mismo modo, si ejecutas pruebas de unidades con Robolectric, es posible que encuentres problemas si tus pruebas dependen del modo Looper heredado.

Acción

Actualiza a Robolectric 4.17 o una versión posterior. Si usas @LooperMode(LEGACY), deberás migrar tus pruebas al nuevo @LooperMode(PAUSED). Consulta la guía de migración de Robolectric para obtener más información.

Prueba el comportamiento

Puedes probar tu app con el cambio de comportamiento en Android 17 sin actualizar targetSDK ejecutando el siguiente comando:

adb am compat enable USE_NEW_MESSAGEQUEUE <your-package-name>

Este comando habilita el MessageQueue sin bloqueo en tu app, si se trata de una compilación depurable.

Si tu app se segmenta para Android 17, el nuevo comportamiento se habilita de forma predeterminada. Si observas fallas o comportamientos inesperados después de segmentar tu app para este nivel de API, puedes inhabilitar temporalmente la nueva implementación para verificar si MessageQueue es la causa.

Puedes activar o desactivar el cambio con cualquiera de las siguientes dos opciones:

  1. El menú Cambios en la compatibilidad de la app en Opciones para desarrolladores.

  2. Ejecuta el siguiente comando de ADB:

    adb am compat disable USE_NEW_MESSAGEQUEUE <your-package-name>
    

Esto revierte tu app a la implementación heredada basada en bloqueos, lo que te permite identificar si el problema se debió a un cambio en el comportamiento de la cola de mensajes.