ANR全名Application Not Responding, 也就是"應(yīng)用無響應(yīng)". 當(dāng)操作在一段時間內(nèi)系統(tǒng)無法處理時, 系統(tǒng)層面會彈出上圖那樣的ANR對話框.
產(chǎn)生ANR原因
在Android里, App的響應(yīng)能力是由Activity Manager和Window Manager系統(tǒng)服務(wù)來監(jiān)控的. 通常在如下兩種情況下會彈出ANR對話框:
- 5s內(nèi)無法響應(yīng)用戶輸入事件(例如鍵盤輸入, 觸摸屏幕等).
- BroadcastReceiver在10s內(nèi)無法結(jié)束.
造成以上兩種情況的首要原因就是在主線程(UI線程)里面做了太多的阻塞耗時操作, 例如文件讀寫, 數(shù)據(jù)庫讀寫, 網(wǎng)絡(luò)查詢等等.
如何避免ANR
知道了ANR產(chǎn)生的原因, 那么想要避免ANR, 也就很簡單了, 就一條規(guī)則:
不要在主線程(UI線程)里面做繁重的操作.
可能產(chǎn)生ANR的條件
- 普通阻塞導(dǎo)致的ANR
- CPU滿負荷即硼,這時候一般會在 trace中最后一句看到(100%TOTAL: 5.9% user + 4.1% kernel + 89% iowait)
- 內(nèi)存原因(其實內(nèi)存原因有可能會導(dǎo)致ANR, 例如如果由于內(nèi)存泄露, App可使用內(nèi)存所剩無幾, 我們點擊按鈕啟動一個大圖片作為背景的activity, 就可能會產(chǎn)生ANR)
ANR的處理
針對三種不同的情況, 一般的處理情況如下
- 主線程阻塞的
開辟單獨的子線程來處理耗時阻塞事務(wù).
- CPU滿負荷, I/O阻塞的
I/O阻塞一般來說就是文件讀寫或數(shù)據(jù)庫操作執(zhí)行在主線程了, 也可以通過開辟子線程的方式異步執(zhí)行.
- 內(nèi)存不夠用的
增大VM內(nèi)存, 使用largeHeap屬性, 排查內(nèi)存泄露(這個在內(nèi)存優(yōu)化那篇細說吧)等.
知識點
哪些地方是執(zhí)行在主線程的
- Activity的所有生命周期回調(diào)都是執(zhí)行在主線程的.
- Service默認是執(zhí)行在主線程的.
- BroadcastReceiver的onReceive回調(diào)是執(zhí)行在主線程的.
- 沒有使用子線程的looper的Handler的handleMessage, post(Runnable)是執(zhí)行在主線程的.
- AsyncTask的回調(diào)中除了doInBackground, 其他都是執(zhí)行在主線程的.
- View的post(Runnable)是執(zhí)行在主線程的.
使用子線程的方式有哪些
- 啟Thread方式(繼承Thread卒密、實現(xiàn)Runnable接口)
- 使用AsyncTask
- HandlerThread
- IntentService
- Loader