MessageQueue 行为变更指南

从 Android 17 开始,以 Android 17 或更高版本为目标平台的应用会收到 android.os.MessageQueue 的新无锁实现。新实现可提升性能并减少丢帧,但可能会破坏依赖于 MessageQueue 私有字段和方法的客户端。

Android 17 通过重写底层 MessageQueue 类,对 LooperHandler 的工作方式进行了重大改进。自 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 级别为目标平台后发现意外行为或崩溃,可以暂时停用新实现,以验证 MessageQueue 是否是导致问题的原因。

您可以使用以下两种方法中的任一种来切换更改:

  1. 开发者选项中的应用兼容性变更菜单

  2. 通过运行以下 ADB 命令:

    adb am compat disable USE_NEW_MESSAGEQUEUE <your-package-name>
    

这会将您的应用恢复为基于锁的旧版实现,从而让您能够确定问题是否是由消息队列行为变更导致的。