Ab Android 17 erhalten Apps, die auf Android 17 (API-Level 37) oder höher ausgerichtet sind, eine neue sperrfreie Implementierung von android.os.MessageQueue. Die neue Implementierung verbessert die Leistung und reduziert verpasste Frames, kann aber Clients beeinträchtigen, die private Felder und Methoden von MessageQueue reflektieren.
Android 17 führt eine grundlegende Überarbeitung der Funktionsweise von Looper und Handler ein, indem die zugrunde liegende MessageQueue-Klasse neu geschrieben wird.
Seit der ersten Version des Android-Betriebssystems wurde in MessageQueue eine einzige Sperre verwendet, um die Aufgabenwarteschlange des Hauptthreads zu verwalten. Dieses Design führte häufig zu Sperrkonflikten. Der Hauptthread konnte durch einen Hintergrundthread blockiert werden, was zu ausgelassenen Frames und UI-Rucklern führte.
Auswirkungen minimieren
Ihre App kann von dieser Änderung betroffen sein, wenn sie oder ihre Abhängigkeiten auf Laufzeitreflexion angewiesen sind, um MessageQueue zu prüfen. Vermeiden Sie die Verwendung von Laufzeitreflexion, um MessageQueue zu prüfen.
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.
Aus Gründen 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 gängige Testbibliotheken verwenden, müssen Sie diese außerdem 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 korrekt zu bestätigen. Frühere Versionen von Espresso basierten auf Reflexionstechniken, die nicht mehr mit der sperrfreien MessageQueue kompatibel sind.
Aktion
Aktualisieren Sie auf Espresso 3.7.0 oder höher. Diese Version verwendet die TestLooperManager API, insbesondere neue APIs, die in Android 16 eingeführt wurden, um sicher mit dem Looper zu interagieren, ohne sich auf interne Implementierungsdetails verlassen zu müssen.
Robolectric
Wenn Sie Unittests mit Robolectric ausführen, können ebenfalls 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 zum neuen @LooperMode(PAUSED) migrieren. Weitere Informationen finden Sie im Migrationsleitfaden von Robolectric.
Verhalten testen
Sie können Ihre App mit der Verhaltensänderung unter 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, wenn 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 Sie nach der Ausrichtung auf dieses API-Level unerwartetes Verhalten oder Abstürze feststellen, können Sie die neue Implementierung vorübergehend deaktivieren, um zu prüfen, ob MessageQueue die Ursache ist.
Sie können die Änderung mit einer der folgenden beiden Optionen aktivieren oder deaktivieren:
Das Menü Änderungen an der App-Kompatibilität in den Entwickleroptionen.
Führen Sie den folgenden ADB-Befehl aus:
adb am compat disable USE_NEW_MESSAGEQUEUE <your-package-name>
Dadurch wird die App auf die alte, sperrbasierte Implementierung zurückgesetzt. So können Sie feststellen, ob das Problem auf eine Änderung des Verhaltens der Nachrichtenwarteschlange zurückzuführen ist.