自 Android 17 起,指定 Android 17 以上版本的應用程式會收到 android.os.MessageQueue 的新實作方式,不會發生鎖定情形。新實作方式可提升效能並減少遺失的影格,但可能會中斷反映 MessageQueue 私有欄位和方法的用戶端。
Android 17 大幅翻新 Looper 和 Handler 的運作方式,重新編寫基礎 MessageQueue 類別。自 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 級別後發現非預期行為或當機情況,可以暫時停用新實作方式,確認 MessageQueue 是否為原因。
你可以使用下列任一方式切換變更:
「開發人員選項」中的「應用程式相容性變更」選單。
執行下列 ADB 指令:
adb am compat disable USE_NEW_MESSAGEQUEUE <your-package-name>
這會將應用程式還原為舊版實作 (以鎖定為基礎),方便您判斷問題是否是由於訊息佇列行為異動所致。