MessageQueue 行為變更指南

從 Android 17 開始,指定 Android 17 (API 級別 37) 以上版本的應用程式會收到新的無鎖定 android.os.MessageQueue 實作。新實作方式可提升效能並減少影格遺漏,但可能會破壞反映 MessageQueue 私人欄位和方法的用戶端。

Android 17 重新編寫了底層 MessageQueue 類別,大幅翻新 Looper 和 Handler 的運作方式。自 Android 作業系統首次發布以來,MessageQueue 一直仰賴單一鎖定來管理主執行緒的工作佇列。這種設計經常導致鎖定爭用,主執行緒可能會遭到背景執行緒封鎖,導致影格遺失和 UI 卡頓。

降低影響

如果應用程式或其依附元件仰賴執行階段反射來查看 MessageQueue 內部,則可能會受到這項異動影響。避免使用執行階段反射來檢查 MessageQueue。

使用舊版實作時,開發人員有時會存取 MessageQueue.mMessages 等私人欄位,檢查待處理訊息。採用新的無鎖定實作後,內部資料結構已完全改變。為維持二進位相容性,Android 17 會保留 mMessages 欄位,但在新的實作中,無論佇列中是否有訊息,這個欄位一律為空值。

此外,如果您使用一些熱門的測試程式庫,則需要更新程式庫,才能與新的 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 的遷移指南。

測試行為

如要測試應用程式在 Android 17 上的行為變更,而不更新 targetSDK,請執行下列指令:

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

如果應用程式是可偵錯的版本,這個指令會在應用程式中啟用無鎖定 MessageQueue。

如果應用程式指定 Android 17 (API 級別 37) 為目標,系統預設會啟用新行為。如果指定這個 API 級別後,發現非預期行為或當機情形,可以暫時停用新實作,確認是否為 MessageQueue 造成。

您可以透過下列任一選項切換變更:

  1. 開發人員選項中的「應用程式相容性變更」選單。

  2. 執行下列 ADB 指令:

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

這會將應用程式還原為舊版、以鎖定為基礎的實作,讓您判斷問題是否為訊息佇列行為變更所致。