![](https://developer.android.com/static/images/anr.png?authuser=0000&hl=zh-tw)
圖 1 向使用者顯示的 ANR 對話方塊。
本文說明 Android 系統如何判斷應用程式沒有回應,以及如何讓應用程式維持回應速度。
無論程式碼編寫得多好,應用程式都有可能出現遲的情況、停止運作、長時間停止運作或處理輸入所需的時間過長。如果您的應用程式在前景執行且沒有回應,使用者會看到應用程式無回應 (ANR) 對話方塊,如圖 1 所示。ANR 對話方塊可讓使用者強制退出應用程式。如果應用程式不在前景,就會自動停止。請務必為應用程式設計回應速度,盡可能減少 ANR 對話方塊。
ANR 觸發條件
一般來說,如果應用程式無法回應主執行緒上的使用者輸入內容 (也稱為 UI 執行緒),導致系統無法處理傳入的使用者輸入事件,系統就會顯示 ANR。
舉例來說,如果應用程式在 UI 執行緒上執行封鎖 I/O 作業 (例如網路存取權),就會發生 ANR。另一個例子是,當應用程式花太多時間建構複雜的記憶體內結構,或在 UI 執行緒上計算遊戲的下一個動作時。
在 Android 中,ActivityManager
和 WindowManager
系統服務會監控應用程式回應速度。當 Android 偵測到以下任一條件,就會顯示 ANR 對話方塊:
- 5 秒內沒有回應輸入事件 (例如按鍵或螢幕輕觸事件)。
- 如果是前景意圖,
BroadcastReceiver
不會在 10 到 20 秒內完成執行。詳情請參閱「廣播接收器逾時」。
避免 ANR
以下是避免 ANR 的一般提示。如要進一步瞭解如何診斷及偵錯不同類型的 ANR,請參閱本節的其他頁面。
讓主執行緒隨時保持解鎖狀態,並策略性使用執行緒。
請勿在應用程式主執行緒上執行封鎖或長時間執行的作業。請改為建立工作站執行緒,並在其中執行大部分的工作。
請盡量減少主執行緒和其他執行緒之間的鎖定爭用。
盡量減少主要執行緒上的任何非 UI 相關工作,例如處理廣播或執行中的服務時。在 UI 執行緒中執行的任何方法,都必須盡可能減少在該執行緒上的工作。請特別注意,在關鍵生命週期方法 (例如
onCreate()
和onResume()
) 中設定活動時,必須盡可能執行。如要進一步瞭解可用於在背景執行緒上排程工作,並與 UI 傳回通訊的解決方案,請參閱「背景工作總覽」。在不同元件之間共用執行緒集區時請務必小心。請不要使用相同的執行緒,來處理可能需要較長的時間封鎖的作業,以及廣播接收等具時效性的工作。
加快應用程式啟動速度。盡量減少應用程式啟動程式碼中緩慢或封鎖的作業,例如在 Dagger 初始化期間執行的方法。
如果您使用
BroadcastReceiver
,請考慮使用Context.registerReceiver
在非主執行緒中執行廣播接收器。詳情請參閱「BroadcastReceiver 中的 ANR」一文。- 如果您使用
goAsync()
,請務必在 ANR 逾時前快速呼叫PendingResult.finish
。
- 如果您使用
BroadcastReceiver 中的 ANR
BroadcastReceiver
的執行時間會受到限制,因為廣播接收器是用來在背景執行少量獨立的工作 (例如儲存設定或註冊 Notification
)。因此,就像 UI 執行緒中呼叫的其他方法一樣,應用程式必須避免廣播接收器中可能長時間執行的作業或計算。請勿透過 UI 執行緒執行長時間執行的工作,而是在背景執行這些工作以便稍後執行。如要進一步瞭解可能的解決方案,請參閱「背景工作總覽」。
BroadcastReceiver
物件的另一個常見問題是,當其執行頻率過高時。經常在背景執行可能會減少其他應用程式可用的記憶體量。如要進一步瞭解如何有效率地啟用和停用 BroadcastReceiver
物件,請參閱「廣播總覽」。
強化反應
一般來說,100 至 200 毫秒是超過使用者認為應用程式緩慢情形的門檻。以下是讓應用程式介面回應使用者的其他訣竅:
如果應用程式是為了回應使用者輸入內容而在背景執行工作,請提供進度,例如:在 UI 中使用
ProgressBar
。針對遊戲,系統會針對背景工作執行緒中的移動進行計算。
如果應用程式的初始設定階段相當耗時,請考慮顯示啟動畫面或盡快轉譯主要檢視畫面。表示系統正在進行載入作業,並以非同步方式填入資訊。無論是哪一種情況,我們都建議您說明進度的進行方式,這樣使用者就不會察覺應用程式停止運作。