A partire da Android 17, le app che hanno come target Android 17 (livello API 37) o versioni successive ricevono una nuova implementazione senza blocchi di android.os.MessageQueue. La nuova implementazione migliora le prestazioni e riduce i frame persi, ma potrebbe interrompere i client che riflettono sui campi e sui metodi privati di MessageQueue.
Android 17 introduce una revisione significativa del funzionamento di Looper e Handler, riscrivendo la classe MessageQueue sottostante.
Dalla prima versione del sistema operativo Android, MessageQueue si è basato su un singolo blocco per gestire la coda di attività del thread principale. Questo design spesso causava conflitti di blocco; il thread principale poteva essere bloccato da un thread in background, con conseguente perdita di frame e jank dell'interfaccia utente.
Mitigare l'impatto
La tua app potrebbe essere interessata da questa modifica se l'app o le sue dipendenze si basano sulla reflection di runtime per esaminare MessageQueue. Evita di utilizzare la reflection di runtime per ispezionare MessageQueue.
Con l'implementazione precedente, gli sviluppatori a volte accedevano a campi privati come MessageQueue.mMessages per ispezionare i messaggi in attesa. Con la nuova
implementazione senza blocchi, le strutture di dati interne sono cambiate completamente.
Per mantenere la compatibilità binaria, Android 17 mantiene il campo mMessages, ma nella nuova implementazione questo campo è sempre null, indipendentemente dalla presenza di messaggi nella coda.
Inoltre, se utilizzi alcune librerie di test popolari, dovrai aggiornarle per renderle compatibili con la nuova implementazione di MessageQueue.
Espresso
Espresso viene comunemente utilizzato per i test della UI. La libreria Espresso deve sapere quando il thread principale è inattivo per eseguire correttamente l'assert sullo stato della UI. Le versioni precedenti di Espresso si basavano su tecniche di riflessione che non sono più compatibili con la MessageQueue senza blocchi.
Azione
Esegui l'aggiornamento a Espresso 3.7.0 o versioni successive. Questa versione utilizza l'API TestLooperManager, in particolare le nuove API introdotte da Android 16, per interagire in sicurezza con Looper senza fare affidamento sui dettagli di implementazione interna.
Robolectric
Analogamente, se esegui test delle unità utilizzando Robolectric, potresti riscontrare problemi se i test si basano sulla modalità Looper precedente.
Azione
Esegui l'aggiornamento a Robolectric 4.17 o versioni successive. Se utilizzi @LooperMode(LEGACY),
dovrai eseguire la migrazione dei test alla nuova @LooperMode(PAUSED). Per saperne di più, consulta la guida alla migrazione di Robolectric.
Testa il comportamento
Puoi testare la tua app con la modifica del comportamento su Android 17 senza aggiornare
targetSDK eseguendo il seguente comando:
adb am compat enable USE_NEW_MESSAGEQUEUE <your-package-name>
Questo comando attiva l'MessageQueue senza blocchi nella tua app, se si tratta di una build abilitata al debug.
Se la tua app ha come target Android 17 (livello API 37), il nuovo comportamento è attivo per impostazione predefinita. Se noti un comportamento imprevisto o arresti anomali dopo aver scelto come target questo livello API, puoi disattivare temporaneamente la nuova implementazione per verificare se la causa è MessageQueue.
Puoi attivare o disattivare la modifica utilizzando una delle due opzioni:
Il menu Modifiche relative alla compatibilità delle app in Opzioni sviluppatore.
Eseguendo il seguente comando ADB:
adb am compat disable USE_NEW_MESSAGEQUEUE <your-package-name>
In questo modo, l'app torna all'implementazione precedente basata su blocchi, consentendoti di identificare se il problema è stato causato da una modifica del comportamento della coda di messaggi.