Leitfaden zur Verhaltensänderung bei MessageQueue

Ab Android 17 erhalten Apps, die auf Android 17 oder höher ausgerichtet sind, eine neue sperrenfreie Implementierung von android.os.MessageQueue. Die neue Implementierung verbessert die Leistung und reduziert fehlende Frames, kann aber 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 ausgelassenen Frames 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 MessageQueue zu untersuchen. 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 behält Android 17 das Feld mMessages bei. 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 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 im Leerlauf ist, um den UI-Status richtig zu bestätigen. Frühere Versionen von Espresso basierten auf Reflection-Techniken, die nicht mehr mit der lock-free MessageQueue kompatibel sind.

Aktion

Aktualisieren Sie auf Espresso 3.7.0 oder höher. 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 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, sofern es sich um einen debugfähigen Build handelt.

Wenn Ihre App auf Android 17 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:

  1. Das Menü Änderungen bei der App-Kompatibilität in den Entwickleroptionen

  2. 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 Verhaltens der Nachrichtenwarteschlange zurückzuführen ist.