上帝說要有ANR,因而Bugly就有了ANR上報。那麼ANR到底是什麼?java
近期很是多童鞋問起精神哥ANR的問題,那麼此次就來聊一下,雞爪怎麼泡纔好吃。噢不,是怎樣高速定位ANR。數據庫
ANR是什麼
簡單說,一般就是App執行的時候,duang~卡住了。怎麼搞都動不了。安全
當卡住超過必定時間。Android系統以爲這就是一次「ANR(Application Not Responding)」。網絡
詳細說。在下面狀況發生時,會發生ANR(可能在不一樣ROM 中時間有所更改):app
用戶的輸入在5s內沒被App響應。函數
BroadcastReceiver的onReceiver()超過10s;性能
Service中各生命週期函數運行超過20s。動畫
ANR必須死
用戶在App的絕大部分操做,都需要有App的主動迴應。比方按下button以後button樣式的改變、下拉滾動欄內容的移動、載入資源時的菊花轉轉轉,它們都是「操做-反饋」配對的模式。對於咱們手機上最多見的觸摸操做。0.1s的響應延遲已經有很是明顯的卡頓感了。而對於常見的ANR。用戶至少要等5s以上!ui
發生了ANR,每每會彈出對話框,問用戶是繼續等待仍是直接關掉:spa
相信差點兒所有Android手機用戶都見過這個然並卵的ANR對話框,但大部分普通用戶根本不知道這個對話框在講什麼,並且每每也僅僅有關閉App。
漫長的等待就給我看這個?從用戶的體驗看,就是心中一萬僅僅草泥馬奔騰起來撞火車的感覺。可見ANR對於應用的影響並不亞於Crash。
通常來講,界面相對越不「流暢」的App(說明UI線程耗時操做多)越easy發生ANR(一個輸入事件在某個設備A上4秒有了反饋。並不意味着它在其它設備B上是安全的)。
ANR事實上就是界面卡頓的極端狀況。反過來,僅僅要經過合理的方案消滅了App出現的ANR,每每也同一時候會使App展現界面表現會更加順滑流暢。
一些典型的ANR 問題場景
這裏舉幾個easy發生ANR的場景:
1)最多見的錯誤,UI線程等待其餘線程釋放某個鎖,致使UI線程沒法處理用戶輸入。
2)遊戲中每幀動畫都進行了比較耗時的大量計算,致使CPU忙只是來;
3)Web應用中。網絡狀態不穩定。而界面在等待網絡數據;
4)UI線程中進行了一些磁盤IO(包含數據庫、SD卡等等)的操做。在個別設備上因爲硬件損壞等緣由堵塞住了;
5)手機被其它App佔用着CPU。本身獲取不到足夠的CPU 時間片,純屬誤傷。
經過ANR 日誌定位問題
當ANR發生時。咱們每每經過Logcat和traces文件(文件夾/data/anr/)的相關信息輸出去定位問題。主要包括下面幾方面:
1)基本信息,包含進程名、進程號、包名、系統build號、ANR 類型等等;
2)CPU使用信息。包含活躍進程的CPU 平均佔用率、IO狀況等等。
3)線程堆棧信息。所屬進程包含發生ANR的進程、其父進程、近期有活動的3個進程等等。
這裏舉個簡單的樣例(實際上因爲各App所處環境各異,可能出現各類各樣複雜的ANR狀況)當App執行卡住,彈出ANR對話框。查看Logcat輸出:
ActivityManager: ANR in com.tencent.bugly.demo (com.tencent.bugly.demo/.MainActivity) ActivityManager: PID: 18617 ActivityManager: Reason: Input dispatching timed out (Waiting because the touched window has not finished processing the input events that were previously delivered to it.) ActivityManager: Load: 18.42 / 18.09 / 18.29 ActivityManager: CPU usage from 5924ms to 475ms ago: ActivityManager: 93% 18617/com.tencent.bugly.demo: 93% user + 0% kernel / faults: 75 minor …… ActivityManager: CPU usage from 2906ms to 3429ms later: ActivityManager: 96% 18617/com.tencent.bugly.demo: 96% user + 0% kernel …… ActivityManager: 55% TOTAL: 51% user + 3.8% kernel
分析一下,從Logcat可以獲得下面信息:
com.tencent.bugly.demo這個App的MainActivity發生了ANR,進程號18617;
ANR緣由:用戶輸入超時。
ANR發生前、後一段時間分別附在狀況:在ANR發生先後,CPU有90+%耗費在這個demo上,說明很是多是這個demo自身性能引發的。
接下來再看traces文件確認:
----- pid 18617 at xxxx ----- Cmd line: com.tencent.bugly.demo JNI: CheckJNI is off; workarounds are off; pins=0; globals=272 (plus 2 weak) DALVIK THREADS: "main" prio=5 tid=1 SUSPENDED | group="main" sCount=1 dsCount=0 obj=0x415e4e58 self=0x415d3028 | sysTid=18617 nice=0 sched=0/0 cgrp=apps handle=1074372948 | state=S schedstat=( 38588000572 591063492 5767 ) utm=3846 stm=12 core=0 at com.tencent.bugly.demo.MainActivity$3.doCalc(MainActivity.java:~38) at com.tencent.bugly.demo.MainActivity$3.onClick(MainActivity.java:33) ……
分析一下,traces文件裏包括下面信息:
一、進程號:18617;包名:com.tencent.bugly.demo。
二、發生ANR時,main線程被掛起(也多是其它等待狀態,比方TIMED_WAIT);
三、線程的幾個重要參數:
group:線程組名稱「main」;
sCount:Suspended個數「1」。
obj:線程的Java對象地址。
self:線程的Native對象地址;
sysTid:線程號(這裏主線程的線程號=進程號)「18617」。
四、詳細堆棧:從堆棧可以很是清晰看出是doCalc()方法出的問題,由onClick觸發。
綜合以上分析。問題還原爲:com.tencent.bugly.demo這個App的MainActivity中有個耗時的doCalc方法在跑。沒法響應用戶的觸摸或按鍵輸入。OK。接下來在代碼裏找問題就行了。
怎樣解決ANR
固然是儘量下降UI線程的耗時操做。以及BroadcastReceiver、Service生命週期中的標準回調方法啦。
Android官方文檔建議:
1)使用AsyncTask類,可以很是方便地實現子線程耗時操做與UI更新;
2)對於BroadcastReceiver的耗時操做。建議放到Service中運行。
3)對於自建的Thread,可以經過Handler使之與UI 線程通訊(這裏需要注意的是。Thread默認優先級和UI線程是同樣的,建議設置通常線程優先級爲Process.THREAD_PRIORITY_BACKGROUND)。
這些方案你們應該都知道。只是仍不免有大量的ANR是寫代碼時忽略了,在測試時沒發生,終於在用戶的手機上出現的。回憶一下是否是都經歷過用戶會反饋「App卡死沒反應了」。但開發GG客服MM們卻又因爲缺乏日誌或沒法復現而一籌莫展?所以要修復ANR。首先是要能發現用戶ANR了。並且能知道是哪段代碼致使ANR了,這樣才幹談修復。
爲了幫助廣大開發人員解決這一難題,騰訊Bugly針對iOS的卡頓及Android的ANR提供監測服務即將上線,協助開發人員輕鬆定位問題。