天天看點

聊聊 Android ANR 那點事兒

聊聊 Android 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,如 Systrace 和 Traceview 。

關于記憶體洩露分析可以檢視之前總結的 Android 記憶體洩漏工具使用分析

如果有錯,歡迎大家指正!

參考

官方文檔

Android 記憶體洩漏工具使用分析

Keeping Your App Responsive

繼續閱讀