从 Android 17 开始,以 Android 17(API 级别 37)或更高版本为目标平台的应用会收到 android.os.MessageQueue 的全新无锁实现。新实现可提升性能并减少丢帧,但可能会破坏反映 MessageQueue 私有字段和方法的客户端。
Android 17 通过重写底层 MessageQueue 类,对 Looper 和 Handler 的运作方式进行了重大调整。自 Android 操作系统首次发布以来,MessageQueue 一直依赖单个锁来管理主线程的任务队列。这种设计经常导致锁争用;主线程可能会被后台线程阻塞,从而导致丢帧和界面卡顿。
减轻影响
如果您的应用或其依赖项依赖于运行时反射来窥探 MessageQueue 内部,则您的应用可能会受到此变更的影响。避免使用运行时反射来检查 MessageQueue。
在旧版实现中,开发者有时会访问 MessageQueue.mMessages 等私有字段来检查待处理的消息。采用新的无锁实现后,内部数据结构已完全改变。
为了保持二进制兼容性,Android 17 保留了 mMessages 字段,但在新实现中,无论队列中是否有消息,此字段始终为 null。
此外,如果您使用一些常用的测试库,则需要更新这些库,使其与新的 MessageQueue 实现兼容。
Espresso
Espresso 通常用于界面测试。Espresso 库需要知道主线程何时处于空闲状态,以便正确断言界面状态。早期版本的 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>
如果您的应用是可调试 build,此命令会在应用中启用无锁 MessageQueue。
如果您的应用以 Android 17(API 级别 37)为目标平台,则默认启用新行为。如果您在以该 API 级别为目标平台后发现异常行为或崩溃,可以暂时停用新实现,以验证 MessageQueue 是否是原因。
您可以通过以下两种方式之一切换此更改:
运行以下 ADB 命令:
adb am compat disable USE_NEW_MESSAGEQUEUE <your-package-name>
这会将您的应用还原为基于锁定的旧版实现,以便您确定问题是否由消息队列行为变更引起。