前言
最近在開發(fā)時遇到Anr(應(yīng)用程序未響應(yīng))問題,由于開發(fā)經(jīng)驗比較少,所以還是第一次遇到這種問題,想要解決這類問題還是要從Anr產(chǎn)生的原因,Anr日志分析、如何避免Anr入手。
Anr產(chǎn)生的原因
一般的產(chǎn)生原因都是在該完成的時間內(nèi)未完成相關(guān)操作,如果超過預(yù)定時間能未能得到有效響應(yīng)或者響應(yīng)時間過長,都會造成 ANR。產(chǎn)生的場景大致分為以下4種:
1、Service Timeout:比如前臺服務(wù)在 20s 內(nèi)未執(zhí)行完成;
2、BroadcastQueue Timeout:比如前臺廣播在 10s 內(nèi)未執(zhí)行完成;
3、ContentProvider Timeout:內(nèi)容提供者,在 publish 過超時 10s;
4、InputDispatching Timeout:輸 件。
Anr日志抓取
對于Anr日志的抓取,Android系統(tǒng)已經(jīng)在底層幫我們抓取好了。但是要拿到這個日志還是不容易的,大致步驟如下:
1、電腦usb連接手機(jī),先用命令行測試adb是否可以使用adb devices,如果出現(xiàn)"'adb' 不是內(nèi)部或外部命令,也不是可運(yùn)行的程序",說明你未安裝adb或者未配置環(huán)境,如果時第一種直接去下載adb,第二種的話可以去配置環(huán)境變量,當(dāng)然你也可以打開adb路徑,路徑大致在sdk\platform-tools下,在這個路徑下在試試adb命令吧,提醒下如果你是在PowerShell下敲命令在adb前需要加上./,例如"./adb devices",才能正常運(yùn)行。
2、查看Anr日志文件夾
執(zhí)行命令 adb shell -> cd data/anr -> ls 即可查看anr文件夾下的trace日志。
3、將trace.text拷貝出來
由于文檔一直存在手機(jī)種,為了方便排查問題我們需要將文檔拷貝出來,拷貝過程中遇到了種種問題,最大的問題還是提示權(quán)限不足,如果你是root用戶可以很簡單的拷貝出來,但是考慮到目前大部分手機(jī)都很難解鎖,使用"adb bugreport xxx(文件名)"可以將文件壓縮拷貝至adb所在目錄下。
Anr解決方法
絕大部分Anr都是因為在主線程執(zhí)行了耗時操作導(dǎo)致,所以耗時操作請放在子線程中。使用Thread/HandlerThread時記得setThreadPriority設(shè)置優(yōu)先級,因為默認(rèn)的級別與主線程相同。
Anr日志分析
先從堆棧日志入手,發(fā)生Anr時在Android Studio中可以看到堆棧日志
07-26 17:51:04.442: E/ActivityManager(2258): ANR in com.xxx.xxx(com.xxx.xxx/com..xxx.xxx.activity.MainActivity)
07-26 17:51:04.442: E/ActivityManager(2258): PID: 28560
07-26 17:51:04.442: E/ActivityManager(2258): Reason: Input dispatching timed out (Waiting to send non-key event because the touched window has not finished processing certain input events that were delivered to it over 500.0ms ago. Wait queue length: 11. Wait queue head age: 5573.8ms.)
從上述信息可以大概看出,發(fā)生Anr的類是MainActivity,導(dǎo)致Anr的原因是InputDispatching Timeout,接下來我們分析導(dǎo)出來的trace日志,根據(jù)關(guān)鍵詞查找"DALVIK THREADS",并查看"main"線程日志,

根據(jù)我的日志可以看出主線程等待去鎖 <0x04085a6d> GattStateListenerMgr這個對象,但是被thread11持有著,主線程被thread11阻塞著導(dǎo)致anr。
搜索關(guān)鍵字"<0x04085a6d> ",如下圖可以看住GattStateListenerMgr在這個被locked,到這里原因已經(jīng)分析完畢,我們可以去解決問題了。
