讓應用程式維持正常回應速度

圖 1. 向使用者顯示的 ANR 對話方塊。

本文件說明 Android 系統如何判斷應用程式沒有回應,以及如何確保應用程式提供良好回應。

無論程式碼編寫得多完善,應用程式仍有可能速度緩慢、停止運作、長時間凍結,或耗費太多時間處理輸入內容。如果應用程式在前景執行時沒有回應,使用者會看到「應用程式無回應」(ANR) 對話方塊,如圖 1 所示。使用者可在 ANR 對話方塊中選擇強制退出應用程式。如果應用程式不在前景執行,停止運作時就不會顯示通知。請務必設計應用程式的回應體驗,盡量避免顯示 ANR 對話方塊。

ANR 觸發條件

一般來說,如果應用程式無法在主執行緒 (也稱為 UI 執行緒) 上回應使用者輸入內容,系統就會顯示 ANR,阻止系統處理傳入的使用者輸入事件。

舉例來說,如果應用程式正在 UI 執行緒中執行會造成阻斷的 I/O 作業 (例如網路存取作業),就可能發生 ANR。另外,當應用程式在 UI 執行緒中建構詳細的記憶體內結構,或計算遊戲的後續動作時,如果耗費太多時間,也可能發生 ANR。

在 Android 中,ActivityManagerWindowManager 系統服務會監控應用程式的回應。當 Android 偵測到以下任一情況,就會顯示應用程式 ANR 對話方塊:

  • 未在 5 秒內回應輸入事件 (例如按鍵或螢幕輕觸事件)。
  • BroadcastReceiver 未在 10 到 20 秒內針對前景意圖完成執行作業。詳情請參閱「廣播接收器逾時」。

避免 ANR

以下是避免發生 ANR 的通用秘訣。如要進一步瞭解如何診斷不同類型的 ANR 並加以偵錯,請參閱本節的其他頁面。

  • 確保主執行緒一律不受阻斷,並依策略使用執行緒。

    • 切勿在應用程式主執行緒中執行會造成阻斷或耗時較長的作業。請改用 Kotlin 協同程式,將工作卸載至背景調度工具 (例如 Dispatchers.IODispatchers.Default)。使用 viewModelScope 等機制安全地啟動這些背景工作,或使用 LaunchedEffect 在 Compose 狀態變更時觸發這些工作。

    • 盡量減少主執行緒和其他執行緒之間的鎖定爭用情形。

    • 盡量減少主執行緒上與 UI 無關的工作,例如在處理廣播或執行服務時。在 UI 執行緒中執行的所有方法或函式,都必須盡量避免執行作業。特別是在重要的生命週期方法 (例如 onCreateonResume) 中,務必盡量減少活動設定作業。請勿在可組合函式內直接執行 I/O 或耗用大量資源的阻斷式運算。這會在組成和重組期間封鎖 UI 執行緒。如要進一步瞭解在背景執行緒中排定工作時程及與 UI 通訊時,可以採用哪些解決方案,請參閱「背景工作總覽」。

    • 在不同元件之間共用執行緒集區時,請務必小心。針對可能長時間造成阻斷的作業和具時效性的工作 (例如接收廣播),切勿使用相同的執行緒。

  • 確保應用程式快速啟動。請在應用程式的啟動程式碼中,盡量減少速度緩慢或會造成阻斷的作業,例如在依附元件插入設定期間 (如使用 Hilt) 執行的方法,或是使用 Jetpack 應用程式啟動程式庫初始化的元件。您可以使用基準設定檔啟動設定檔R8,進一步最佳化應用程式啟動程序。

  • 如果使用的是 BroadcastReceiver,請考慮採用 Context.registerReceiver,在非主執行緒中執行廣播接收器。詳情請參閱「BroadcastReceiver 中的 ANR」。

BroadcastReceiver 中的 ANR

BroadcastReceiver 的執行時間會受到限制,因為廣播接收器的用途是在背景執行不固定的少量工作,例如儲存設定或註冊 Notification。因此,就像使用其他在 UI 執行緒中呼叫的方法一樣,應用程式必須在廣播接收器中避免可能會長時間執行的作業或運算。為方便處理後續的執行作業,請在背景執行耗時較長的工作,而不要在 UI 執行緒中執行這類工作。如要進一步瞭解可能的解決方案,請參閱「背景工作總覽」。

另一項與 BroadcastReceiver 物件相關的常見問題,是因為此物件太頻繁執行作業。如果經常在背景執行作業,可能會減少其他應用程式可用的記憶體量。如要進一步瞭解如何迅速啟用及停用 BroadcastReceiver 物件,請參閱「廣播總覽」。

提升回應體驗

一般來說,回應速度的門檻為 100 至 200 毫秒,之後使用者就會感覺應用程式速度緩慢。您可以按照下列補充訣竅操作,讓使用者感覺應用程式提供良好回應:

  • 如果應用程式為了回應使用者輸入內容而在背景執行,請顯示處理進度,例如在 UI 中使用 CircularProgressIndicatorLinearProgressIndicator

  • 請特別針對遊戲,在背景協同程式或背景工作執行緒中計算動作。

  • 如果應用程式的初始設定階段相當耗時,請考慮顯示啟動畫面,或是盡快算繪初始組合。您可以指出正在載入內容,並以非同步方式填入 UI 狀態。不論是哪一種情況,都建議您說明程序正在執行,以免使用者認為應用程式凍結了。

  • 使用 PerfettoCPU 分析器等效能工具,判斷應用程式回應的瓶頸。