Ab Android 17 erhalten Apps, die auf Android 17 (API-Level 37) oder höher ausgerichtet sind, eine neue sperrenfreie Implementierung von android.os.MessageQueue. Die neue Implementierung verbessert die Leistung und reduziert die Anzahl der ausgelassenen Frames. Sie kann jedoch Clients beeinträchtigen, die private Felder und Methoden von MessageQueue verwenden.
In Android 17 wurde die Funktionsweise von Looper und Handler grundlegend überarbeitet. Dazu wurde die zugrunde liegende Klasse MessageQueue neu geschrieben.
Seit der ersten Version des Android-Betriebssystems hat MessageQueue ein einzelnes Lock verwendet, um die Aufgabenwarteschlange des Hauptthreads zu verwalten. Dieses Design führte oft zu Konflikten bei der Sperrung. Der Hauptthread konnte durch einen Hintergrundthread blockiert werden, was zu Frame-Drops und Ruckeln der Benutzeroberfläche führte.
Auswirkungen minimieren
Ihre App ist möglicherweise von dieser Änderung betroffen, wenn sie oder ihre Abhängigkeiten auf Laufzeit-Reflection angewiesen sind, um in MessageQueue zu schauen. Vermeiden Sie die Verwendung von Laufzeitreflexion, um MessageQueue zu untersuchen.
Bei der alten Implementierung haben Entwickler manchmal auf private Felder wie MessageQueue.mMessages zugegriffen, um ausstehende Nachrichten zu prüfen. Mit der neuen sperrenfreien Implementierung haben sich die internen Datenstrukturen vollständig geändert.
Zur Aufrechterhaltung der Binärkompatibilität wird das Feld mMessages in Android 17 beibehalten. In der neuen Implementierung ist dieses Feld jedoch immer null, unabhängig davon, ob sich Nachrichten in der Warteschlange befinden.
Wenn Sie einige beliebte Testbibliotheken verwenden, müssen Sie außerdem Ihre Bibliotheken aktualisieren, damit sie mit der neuen MessageQueue-Implementierung kompatibel sind.
Espresso
Espresso wird häufig für UI-Tests verwendet. Die Espresso-Bibliothek muss wissen, wann der Hauptthread inaktiv ist, um den UI-Status richtig zu bestätigen. Frühere Versionen von Espresso basierten auf Reflection-Techniken, die nicht mehr mit der sperrfreien MessageQueue kompatibel sind.
Aktion
Führen Sie ein Update auf Espresso 3.7.0 oder höher durch. In dieser Version wird die TestLooperManager API verwendet, insbesondere neue APIs, die mit Android 16 eingeführt wurden, um sicher mit dem Looper zu interagieren, ohne auf interne Implementierungsdetails angewiesen zu sein.
Robolectric
Wenn Sie Einheitentests mit Robolectric ausführen, können Probleme auftreten, wenn Ihre Tests auf dem alten Looper-Modus basieren.
Aktion
Aktualisieren Sie auf Robolectric 4.17 oder höher. Wenn Sie @LooperMode(LEGACY) verwenden, müssen Sie Ihre Tests zur neuen @LooperMode(PAUSED) migrieren. Weitere Informationen finden Sie im Migrationsleitfaden für Robolectric.
Verhalten testen
Sie können Ihre App mit der Verhaltensänderung auf Android 17 testen, ohne targetSDK zu aktualisieren. Führen Sie dazu den folgenden Befehl aus:
adb am compat enable USE_NEW_MESSAGEQUEUE <your-package-name>
Mit diesem Befehl wird die sperrfreie MessageQueue in Ihrer App aktiviert, sofern es sich um einen debugfähigen Build handelt.
Wenn Ihre App auf Android 17 (API‑Level 37) ausgerichtet ist, ist das neue Verhalten standardmäßig aktiviert. Wenn nach der Ausrichtung auf dieses API-Level unerwartetes Verhalten oder Abstürze auftreten, können Sie die neue Implementierung vorübergehend deaktivieren, um zu prüfen, ob MessageQueue die Ursache ist.
Sie haben zwei Möglichkeiten, die Änderung zu aktivieren oder zu deaktivieren:
Das Menü Änderungen bei der App-Kompatibilität in den Entwickleroptionen
Führen Sie dazu den folgenden ADB-Befehl aus:
adb am compat disable USE_NEW_MESSAGEQUEUE <your-package-name>
Dadurch wird Ihre App auf die alte, sperrenbasierte Implementierung zurückgesetzt. So können Sie feststellen, ob das Problem auf eine Änderung des Message-Queue-Verhaltens zurückzuführen ist.