A partir de Android 17, las apps orientadas a Android 17 (nivel de API 37) o versiones posteriores reciben una nueva implementación sin bloqueos de android.os.MessageQueue. La nueva implementación mejora el rendimiento y reduce los fotogramas perdidos, pero puede interrumpir los clientes que reflejan los campos y métodos privados de MessageQueue.
Android 17 presenta una revisión significativa de cómo funcionan Looper y Handler, ya que se reescribe la clase MessageQueue subyacente.
Desde la primera versión del sistema operativo Android, MessageQueue dependía
de un solo bloqueo para administrar la lista de tareas en cola del subproceso principal. Este diseño solía
provocar contención de bloqueo; el subproceso principal podía bloquearse por un subproceso en segundo plano,
lo que generaba fotogramas perdidos y bloqueos de la IU.
Mitiga el impacto
Este cambio puede afectar a tu app si esta o sus dependencias se basan en la
reflexión del entorno de ejecución para ver el interior de MessageQueue. Evita usar la reflexión del entorno 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 siempre es nulo, independientemente de si hay mensajes en la cola.
Además, si usas algunas bibliotecas de pruebas 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 confirmar correctamente el estado de la IU. Las versiones anteriores de Espresso dependían de técnicas de reflexión que ya no son compatibles con la 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 APIs nuevas que introdujo Android 16, para interactuar de forma segura con Looper sin depender de los detalles de implementación interna.
Robolectric
Del mismo modo, si ejecutas pruebas de unidades con Robolectric, es posible que tengas 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 es una compilación depurable.
Si tu app se orienta a Android 17 (nivel de API 37), el nuevo comportamiento se habilitará de forma predeterminada. Si notas un comportamiento inesperado o fallas después de segmentar 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 estas dos opciones:
El menú Cambios de compatibilidad con apps en Opciones para desarrolladores
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.