Android官方开发文档Training系列课程中文版:如何避免ANR?
原文地址:http://android.xsoftlab.net/training/articles/perf-anr.html#anr
盡管你寫代碼可能通過了世界上所有的性能測試,但是它還是可能會讓人感覺到卡頓。當(dāng)應(yīng)用卡的不成樣子時,系統(tǒng)會給你彈一個”Application Not Responding”的對話框。
在Android中,系統(tǒng)會對那些長時間沒有響應(yīng)的應(yīng)用采取一些措施:彈出一個對話框告訴用戶APP已經(jīng)停止了響應(yīng),如下圖所示:
正出于這個原因,系統(tǒng)會在APP長時間沒有響應(yīng)的時候?yàn)橛脩籼峁┮粋€退出APP的選項(xiàng)。所以使APP能夠及時響應(yīng)這一點(diǎn)是至關(guān)重要的,這樣系統(tǒng)才不會向用戶顯示ANR對話框。
這節(jié)課我們會學(xué)習(xí)Android系統(tǒng)如何檢測應(yīng)用程序是否是未響應(yīng),以及應(yīng)用程序如何保持響應(yīng)能力的一些改進(jìn)措施。
什么觸發(fā)了ANR?
通常情況下,系統(tǒng)會在應(yīng)用程序不再能夠響應(yīng)用戶的輸入時顯示ANR對話框。比如,如果應(yīng)用阻塞在了UI線程的IO操作上,那么系統(tǒng)就不能夠處理用戶的輸入事件?;蛘邞?yīng)用花費(fèi)了大量的時間在內(nèi)存模型的構(gòu)建上或者是在UI線程中計算了游戲的下一步動作。要記住:
即便是最高效的代碼也需要花費(fèi)時間來運(yùn)行。
任何情況下都不要在UI線程中執(zhí)行耗時操作,而是要將這些工作放在一個單獨(dú)的線程中執(zhí)行。這可以使UI線程保持流暢工作(UI線程負(fù)責(zé)驅(qū)動用戶界面的事件循環(huán))。
在Android中,應(yīng)用程序的響應(yīng)態(tài)由Activity Manager及Window Manager負(fù)責(zé)監(jiān)控。系統(tǒng)會在偵測到以下狀況時顯示ANR對話框:
- 對輸入事件在5秒內(nèi)沒有作出響應(yīng)。
- BroadcastReceiver在10秒內(nèi)沒有執(zhí)行完畢。
如何避免ANR?
Android應(yīng)用程序默認(rèn)運(yùn)行在UI線程中。這意味著在UI線程中的任何耗時操作都會引發(fā)ANR問題,因?yàn)檫@會使應(yīng)用程序給不到輸入事件或者意圖廣播處理的機(jī)會。
因此,在UI線程中的每個方法都應(yīng)當(dāng)做盡可能少的工作,尤其是Activity的生命周期回調(diào)函數(shù)。像網(wǎng)絡(luò)或數(shù)據(jù)庫操作,或者大量的計算之類的耗時操作應(yīng)當(dāng)在工作線程中執(zhí)行。
創(chuàng)建用于執(zhí)行耗時操作的線程最便捷的方式莫過于使用AsyncTask了。只需要繼承AsyncTask,然后重寫doInBackground()就可以執(zhí)行了。如果要向用戶展示工作進(jìn)度,你可以使用publishProgress()方法,它會回調(diào)onProgressUpdate()方法(該方法運(yùn)行于UI線程)。
在onProgressUpdate()內(nèi)我們可以更新進(jìn)度條。
使用execute()方法啟動工作線程:
new DownloadFilesTask().execute(url1, url2, url3);如果不采用這種方式,我們還有另一種實(shí)現(xiàn)方法:創(chuàng)建自己的Thread或HandlerThread。如果采用這種方法,那么應(yīng)該設(shè)置該線程的優(yōu)先級為”background”:通過Process.setThreadPriority()方法及參數(shù)THREAD_PRIORITY_BACKGROUND設(shè)置。
如果沒有設(shè)置該優(yōu)先級,那么該線程會使應(yīng)用感到變慢,因?yàn)樵摼€程的優(yōu)先級默認(rèn)與UI線程的優(yōu)先級一致,它們會互相搶占CPU資源。
如果實(shí)現(xiàn)了自己的Thread或HandlerThread,那么要確保在等待其它工作線程完成之前UI線程不被阻塞—不要調(diào)用Thread.wait()或Thread.sleep()。如果需要等待其它線程的執(zhí)行結(jié)果,可以為UI線程創(chuàng)建一個Handler。這樣做可以使UI線程還可以對
輸入事件保持響應(yīng)能力。這樣就可以避免5秒內(nèi)無響應(yīng)的ANR對話框出現(xiàn)。
BroadcastReceiver在執(zhí)行時間上有特殊的限制,這意味著在其內(nèi)部的工作一定是輕量級的:比如在后臺做一些保存設(shè)置或者發(fā)送通知的工作。所以與UI線程中執(zhí)行的方法一樣,廣播接收器內(nèi)也應(yīng)當(dāng)杜絕耗時操作的出現(xiàn)。
TIP: 你可以使用StrictMode來發(fā)現(xiàn)UI線程中意外出現(xiàn)的耗時操作。
ANR相關(guān)優(yōu)化
一般來說,100~200毫秒是用戶所能感知到應(yīng)用卡頓的極限。下面列出了一些可以避免應(yīng)用程序ANR的一些點(diǎn),同樣也有助于防止出現(xiàn)卡頓的情況:
- 如果應(yīng)用需要對用戶輸入做大量的后臺工作,可以顯示一個進(jìn)度表示工作正在進(jìn)行。
- 對于游戲類的復(fù)雜計算,應(yīng)該將這些工作放在工作線程中執(zhí)行。
- 如果應(yīng)用在初始化階段需要花費(fèi)一些時間,可以考慮顯示一個閃屏頁面或者盡可能快的顯示主界面:展示加載正在進(jìn)行,并進(jìn)行異步數(shù)據(jù)填充。在這些情況下都應(yīng)當(dāng)表明任務(wù)正在進(jìn)行,以免讓用戶認(rèn)為應(yīng)用已經(jīng)卡死。
- 使用Systrace或Traceview等性能工具檢查APP的響應(yīng)瓶頸。
總結(jié)
以上是生活随笔為你收集整理的Android官方开发文档Training系列课程中文版:如何避免ANR?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【HTML/CSS】CSS盒模型及其理解
- 下一篇: Android中使用官方提供好的功能使用