聊聊 Android ANR 那點事兒

ANR 彈窗

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,如 SystraceTraceview

關於內存泄露分析可以查看之前總結的 Android 內存泄漏工具使用分析
如果有錯,歡迎大家指正!

參考

官方文檔
Android 內存泄漏工具使用分析
Keeping Your App Responsive

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章