一、什么是 ANR?
ANR(Application Not Responding) 是 Android 系統在應用程序主線程(UI
線程)被阻塞超過一定時間后觸發的錯誤機制。此時系統會彈出一個對話框提示用戶“應用無響應”,用戶可以選擇等待或強制關閉應用。
ANR 的觸發條件:
- 主線程阻塞超過閾值:
1)輸入事件(如點擊、滑動):5 秒內未處理完成。
2)BroadcastReceiver:前臺廣播 10 秒內未完成,后臺廣播 60 秒內未完成。
3)Service 啟動或綁定:前臺 Service 5 秒內未完成onCreate()或onStartCommand()。 - 主線程執行耗時操作:例如網絡請求、數據庫查詢、文件讀寫等。
二、ANR 的根本原因
- 主線程被阻塞:主線程負責 UI 渲染和事件響應,若執行耗時操作,會直接導致界面卡頓或無響應。
- 過度復雜的布局或繪制:布局嵌套過深、頻繁重繪等。
- 死鎖或過度同步:線程間競爭鎖資源,導致主線程等待。
三、如何避免 ANR?
1、主線程只處理 UI 和輕量操作
1)禁止在主線程執行以下操作:
a)網絡請求(HTTP/HTTPS)。
b) 數據庫查詢(SQLite)。
c) 大文件讀寫。
d) 復雜計算(如循環、加密解密)。
2)正確做法:使用子線程(如 Thread、HandlerThread)或異步框架(如 Kotlin 協程、RxJava、AsyncTask)。
2、使用異步框架處理耗時任務
1)Kotlin 協程:
2)Rxjava
3、 優化主線程任務
1)減少布局復雜度:a) 使用 ConstraintLayout 減少嵌套層級;b) 避免 RelativeLayout 或 LinearLayout 的過度嵌套;c) 使用 ViewStub 延遲加載復雜布局。
2)避免過度繪制:使用 Android Studio 的 Layout Inspector 和 GPU 渲染分析工具 檢測繪制性能
3)分批處理數據:若需渲染大量數據(如列表),使用分頁加載(Paging Library)或增量更新
4、 避免死鎖和過度同步
1)減少鎖競爭:避免在主線程中等待子線程釋放鎖。
2)使用線程安全的數據結構:如 ConcurrentHashMap、CopyOnWriteArrayList
3)謹慎使用 synchronized:盡量縮小同步代碼塊的范圍
5、 監控 ANR 并分析日志
1)ANR 日志:
a) 系統會在 /data/anr/ 目錄下生成 traces.txt 文件,記錄 ANR 時的線程堆棧
b) Android 11 及以上版本可通過 adb bugreport 獲取更詳細的日志
2)第三方監控工具:
a) 使用 Firebase Crashlytics、Bugsnag 等工具捕獲 ANR 事件。
b) 使用 ANR-WatchDog 庫主動檢測 ANR。
通過合理設計線程模型、使用現代異步框架,并結合性能分析工具,可顯著降低 ANR 的發生概率。