ANR 在 Android開發中並不陌生,遇到 ANR 有時讓我們很苦惱,自己平時也遇到過這樣的問題,今天來聊聊 Android 中 ANR 那點事並記錄在此,以防下次遇到我們就知道該如何分析了。
ANR定義
簡單說下官方解釋,ANR,Application Not Responding,即應用程序沒有響應,Android 系統會向用戶顯示一個程序無響應對話框,用戶可以選擇等待或者強制關閉。
出現場景
- 按鍵或觸摸事件 5s 內無響應;
- BroadcastReceiver 10s 內無法處理完成;
- Service 在 20s 時間內無法處理完成;
發生 ANR 基本上都會出現無法響應對話框,除了一些後臺程序的 ANR,造成 ANR 的原因很多,比如:
- UI 主線程被其他操作阻塞;
- 主線程存在耗時操作(本地 IO操作、網絡訪問、循環等);
如何分析
關於發生 ANR 截取的 log 和 trace 這裏就不多說了
1、CPU 問題
- 在 Monkeylog.log 文件中定位到 “anr in” 位置,查看 cpu usage ,total 佔用,如發現接近100%,暫時判斷爲 cpu 問題。
- 然後在 logcat.log 文件中定位到 “not responding” 發生時間,並截取
cpuinfo.log 中時間點前後 5s 的 log,然後計算 CPU 佔中,看哪個進程用的多,在酌情分析模塊的 CPU 佔中。
2、GC 問題
定位到 logcat.log 文件中 “not responding” 發生時間點;
去查看發生 ANR 時間點對應的 trace 文件,定位到應用報名,若Dalvik Thread主線程顯示“SUSPENDED”,則爲內存問題;
截取 ANR 發生時間點前 5s 的 log,分析 “dalvikvm” 打印的 Paused GC 耗時,如果過多則定位爲 GC 問題,需要查看這 5s 件發生了哪些耗時的操作。
注意:發生 GC 的進程 id 需要和當前發生 ANR 的線程 id 的要一致
如何避免
- 合理使用 UI 主線程,耗時操作放入其他線程工作;
- 合理使用 Handler 來處理其他線程請求;
- 合理使用並遵循 Android 生命週期, 避免在 onCreate() and onResume() 做過多的事情;
- 使用一些架構形成規範來避免內存等問題,例如:MVP、RxJava;
- 經常使用工具來檢查內存問題,例如:MAT、TraceView、AS 自帶等工具;
- 避免加載大圖片引起內存不足導致 ANR;
- 避免內存泄露引起的 ANR。
比如官方例子中:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
// Do the long-running work in here
// 耗時操作放這裏
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
// This is called each time you call publishProgress()
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
// This is called when doInBackground() is finished
// 耗時操作完成後 Post 到 UI 主線程
protected void onPostExecute(Long result) {
showNotification("Downloaded " + result + " bytes");
}
}
友好處理
一般情況下, 超過100至200毫秒用戶會感知程序有些緩慢。因此,可以做一些比較友好的 UI 提示頁面,比如:ProgressBar,來表明當前正在處理,使得用戶不會去一直點擊頁面,減少輸入即可能減少 ANR 出現機率,因爲按鍵5s不響應是會出現 ANR 的。
可以使用性能工具來優化我們的 App,如 Systrace 和 Traceview 。
關於內存泄露分析可以查看之前總結的 Android 內存泄漏工具使用分析
如果有錯,歡迎大家指正!