A partir do Android 17, os apps destinados ao Android 17 (nível 37 da API)
ou mais recente recebem uma nova implementação sem bloqueio de
android.os.MessageQueue. A nova implementação melhora o desempenho e
reduz os frames perdidos, mas pode causar falhas em clientes que refletem em campos e métodos particulares
de MessageQueue.
O Android 17 apresenta uma reformulação significativa no funcionamento de Looper e
Handler, reescrevendo a classe MessageQueue.
Desde a primeira versão do sistema operacional Android, o MessageQueue dependia
de um único bloqueio para gerenciar a fila de tarefas da linha de execução principal. Esse design geralmente
causava contenção de bloqueio. A linha de execução principal podia ser bloqueada por uma linha de execução em segundo plano,
levando a frames perdidos e instabilidade na interface.
Mitigar o impacto
Seu app poderá ser afetado por essa mudança se ele ou as dependências dele usarem a
reflexão de tempo de execução para analisar o MessageQueue. Evite usar a reflexão do ambiente de execução
para inspecionar MessageQueue.
Com a implementação legada, os desenvolvedores às vezes acessavam campos particulares,
como MessageQueue.mMessages, para inspecionar mensagens pendentes. Com a nova
implementação sem bloqueio, as estruturas de dados internas mudaram completamente.
Para manter a compatibilidade binária, o Android 17 mantém o campo mMessages, mas, na
nova implementação, esse campo é sempre nulo, independente de haver
mensagens na fila.
Além disso, se você usa algumas bibliotecas de teste conhecidas, precisa atualizá-las
para que sejam compatíveis com a nova implementação de MessageQueue.
Espresso
O Espresso é usado com frequência para testes de interface. A biblioteca Espresso precisa saber quando a linha de execução principal está inativa para declarar corretamente o estado da IU. As versões anteriores do Espresso dependiam de técnicas de reflexão que não são mais compatíveis com a MessageQueue sem bloqueio.
Ação
Atualize para o Espresso 3.7.0 ou mais recente. Essa versão usa a
API TestLooperManager, principalmente as novas APIs introduzidas pelo Android 16,
para interagir com segurança com o Looper sem depender de detalhes de implementação
interna.
Robolectric
Da mesma forma, se você executar testes de unidade usando o Robolectric, poderá encontrar problemas se os testes dependerem do modo Looper legado.
Ação
Atualize para o Robolectric 4.17 ou mais recente. Se você estiver usando @LooperMode(LEGACY),
será necessário migrar seus testes para o novo @LooperMode(PAUSED). Consulte o
guia de migração do Robolectric (link em inglês) para mais informações.
Testar o comportamento
Para testar o app com a mudança de comportamento no Android 17 sem atualizar o
targetSDK, execute o seguinte comando:
adb am compat enable USE_NEW_MESSAGEQUEUE <your-package-name>
Esse comando ativa o MessageQueue sem bloqueio no app, se ele for um
build depurável.
Se o app for direcionado ao Android 17 (nível 37 da API), o novo comportamento será ativado
por padrão. Se você notar um comportamento inesperado ou falhas após segmentar esse
nível da API, desative temporariamente a nova implementação para verificar se
MessageQueue é a causa.
É possível alternar a mudança usando uma das duas opções:
O menu Mudanças na compatibilidade do app em Opções do desenvolvedor.
Execute o seguinte comando do ADB:
adb am compat disable USE_NEW_MESSAGEQUEUE <your-package-name>
Isso reverte o app para a implementação legada baseada em bloqueio, permitindo que você identifique se o problema foi resultado de uma mudança no comportamento da fila de mensagens.