Orientación sobre el cambio de comportamiento de MessageQueue

A partir de Android 17, las apps orientadas a Android 17 (nivel de API 37) 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 interrumpir los clientes que reflejan los campos y métodos privados de MessageQueue.

Android 17 presenta una revisión importante de cómo funcionan Looper y Handler, ya que se reescribe 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; el subproceso principal podía bloquearse con un subproceso en segundo plano, lo que provocaba fotogramas perdidos y que la IU se atasque.

Mitiga el impacto

Tu app puede verse afectada por este cambio si ella o sus dependencias se basan en la reflexión del tiempo de ejecución para mirar dentro de 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 bloqueo, las estructuras de datos internas cambiaron por completo. Para mantener la compatibilidad binaria, Android 17 conserva el mMessages campo, 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 pruebas de IU. La biblioteca de Espresso necesita saber cuándo el subproceso principal está inactivo para realizar aserciones correctamente en 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 TestLooperManager API, en particular las nuevas APIs que introdujo Android 16, para interactuar de forma segura con la Looper sin depender de los detalles de implementación interna.

Robolectric

Del mismo modo, si ejecutas pruebas unitarias 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 MessageQueue sin bloqueo en tu app, si es una compilación depurable.

Si tu app está orientada a Android 17 (nivel de API 37), el nuevo comportamiento está habilitado de forma predeterminada. Si observas un comportamiento o fallas inesperados después de orientar 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 opciones:

  1. El menú Cambios de compatibilidad con apps 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 bloqueo, lo que te permite identificar si el problema fue el resultado del cambio de comportamiento de la cola de mensajes.