Android 17 以降では、Android 17 以降をターゲットとするアプリは、android.os.MessageQueue の新しいロックフリー実装を受け取ります。新しい実装ではパフォーマンスが向上し、フレーム落ちが減少しますが、MessageQueue のプライベート フィールドとメソッドを反映するクライアントが破損する可能性があります。
Android 17 では、基盤となる MessageQueue クラスを書き換えることで、Looper と Handler の動作が大幅に改善されています。Android オペレーティング システムの最初のリリース以来、MessageQueue は単一のロックに依存してメインスレッドのタスクキューを管理していました。この設計では、ロック競合が頻繁に発生していました。メインスレッドがバックグラウンド スレッドによってブロックされ、フレームのドロップや UI ジャンクが発生していました。
影響を軽減する
アプリまたはその依存関係が MessageQueue の内部を調べるために実行時のリフレクションに依存している場合、この変更の影響を受ける可能性があります。ランタイム リフレクションを使用して MessageQueue を検査しないでください。
以前の実装では、デベロッパーが MessageQueue.mMessages などのプライベート フィールドにアクセスして、保留中のメッセージを検査することがありました。新しいロックフリー実装では、内部データ構造が完全に変更されています。バイナリ互換性を維持するため、Android 17 では mMessages フィールドが保持されますが、新しい実装では、キューにメッセージがあるかどうかに関係なく、このフィールドは常に null になります。
また、よく使用されるテスト ライブラリを使用している場合は、新しい MessageQueue 実装と互換性があるようにライブラリを更新する必要があります。
Espresso
Espresso は UI テストでよく使用されます。Espresso ライブラリは、UI の状態を正しくアサートするために、メインスレッドがアイドル状態になったタイミングを把握する必要があります。以前のバージョンの Espresso は、ロックフリーの MessageQueue と互換性のないリフレクション手法に依存していました。
アクション
Espresso 3.7.0 以降に更新します。このバージョンでは、TestLooperManager API(特に Android 16 で導入された新しい API)を使用して、内部実装の詳細に依存することなく Looper と安全にやり取りします。
Robolectric
同様に、Robolectric を使用して単体テストを実行する場合、テストが以前の Looper モードに依存していると、問題が発生する可能性があります。
アクション
Robolectric 4.17 以降にアップデートします。@LooperMode(LEGACY) を使用している場合は、テストを新しい @LooperMode(PAUSED) に移行する必要があります。詳しくは、Robolectric の移行ガイドをご覧ください。
動作をテストする
次のコマンドを実行すると、targetSDK を更新せずに、Android 17 で動作変更を伴うアプリをテストできます。
adb am compat enable USE_NEW_MESSAGEQUEUE <your-package-name>
このコマンドは、アプリがデバッグ可能なビルドの場合、アプリでロックフリーの MessageQueue を有効にします。
アプリが Android 17 をターゲットとする場合、新しい動作はデフォルトで有効になります。この API レベルをターゲットにした後に予期しない動作やクラッシュが発生した場合は、新しい実装を一時的に無効にして、MessageQueue が原因かどうかを確認できます。
次のいずれかのオプションを使用して、変更を切り替えることができます。
[開発者向けオプション] の [アプリの互換性の変更] メニュー。
次の ADB コマンドを実行します。
adb am compat disable USE_NEW_MESSAGEQUEUE <your-package-name>
これにより、アプリが以前のロックベースの実装に戻り、問題がメッセージ キューの動作変更によるものかどうかを特定できます。