前言
最近在開發(fā)時(shí)遇到Anr(應(yīng)用程序未響應(yīng))問題,由于開發(fā)經(jīng)驗(yàn)比較少,所以還是第一次遇到這種問題赛蔫,想要解決這類問題還是要從Anr產(chǎn)生的原因,Anr日志分析泥张、如何避免Anr入手呵恢。
Anr產(chǎn)生的原因
一般的產(chǎn)生原因都是在該完成的時(shí)間內(nèi)未完成相關(guān)操作,如果超過預(yù)定時(shí)間能未能得到有效響應(yīng)或者響應(yīng)時(shí)間過長(zhǎng)圾结,都會(huì)造成 ANR瑰剃。產(chǎn)生的場(chǎng)景大致分為以下4種:
1、Service Timeout:比如前臺(tái)服務(wù)在 20s 內(nèi)未執(zhí)行完成筝野;
2、BroadcastQueue Timeout:比如前臺(tái)廣播在 10s 內(nèi)未執(zhí)行完成粤剧;
3歇竟、ContentProvider Timeout:內(nèi)容提供者,在 publish 過超時(shí) 10s;
4抵恋、InputDispatching Timeout:輸 件焕议。
Anr日志抓取
對(duì)于Anr日志的抓取,Android系統(tǒng)已經(jīng)在底層幫我們抓取好了弧关。但是要拿到這個(gè)日志還是不容易的盅安,大致步驟如下:
1、電腦usb連接手機(jī)世囊,先用命令行測(cè)試adb是否可以使用adb devices,如果出現(xiàn)"'adb' 不是內(nèi)部或外部命令别瞭,也不是可運(yùn)行的程序",說明你未安裝adb或者未配置環(huán)境,如果時(shí)第一種直接去下載adb株憾,第二種的話可以去配置環(huán)境變量蝙寨,當(dāng)然你也可以打開adb路徑,路徑大致在sdk\platform-tools下嗤瞎,在這個(gè)路徑下在試試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用戶可以很簡(jiǎn)單的拷貝出來郑藏,但是考慮到目前大部分手機(jī)都很難解鎖,使用"adb bugreport xxx(文件名)"可以將文件壓縮拷貝至adb所在目錄下瘩欺。
Anr解決方法
絕大部分Anr都是因?yàn)樵谥骶€程執(zhí)行了耗時(shí)操作導(dǎo)致必盖,所以耗時(shí)操作請(qǐng)放在子線程中。使用Thread/HandlerThread時(shí)記得setThreadPriority設(shè)置優(yōu)先級(jí)俱饿,因?yàn)槟J(rèn)的級(jí)別與主線程相同歌粥。
Anr日志分析
先從堆棧日志入手,發(fā)生Anr時(shí)在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這個(gè)對(duì)象棉圈,但是被thread11持有著涩堤,主線程被thread11阻塞著導(dǎo)致anr。
搜索關(guān)鍵字"<0x04085a6d> ",如下圖可以看住GattStateListenerMgr在這個(gè)被locked分瘾,到這里原因已經(jīng)分析完畢胎围,我們可以去解決問題了。