从 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 的迁移指南。
测试行为
您可以在 Android 17 上测试应用的行为变更,而无需更新 targetSDK,只需执行以下命令:
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>
这会将您的应用恢复为旧版基于锁的实现,以便您确定问题是否是由消息队列行为变更导致的。