編輯:關於Android編程
盡管你寫代碼可能通過了世界上所有的性能測試,但是它還是可能會讓人感覺到卡頓。當應用卡的不成樣子時,系統會給你彈一個”Application Not Responding”的對話框。
在Android中,系統會對那些長時間沒有響應的應用采取一些措施:彈出一個對話框告訴用戶APP已經停止了響應,如下圖所示:
正出於這個原因,系統會在APP長時間沒有響應的時候為用戶提供一個退出APP的選項。所以使APP能夠及時響應這一點是至關重要的,這樣系統才不會向用戶顯示ANR對話框。
這節課我們會學習Android系統如何檢測應用程序是否是未響應,以及應用程序如何保持響應能力的一些改進措施。
通常情況下,系統會在應用程序不再能夠響應用戶的輸入時顯示ANR對話框。比如,如果應用阻塞在了UI線程的IO操作上,那麼系統就不能夠處理用戶的輸入事件。或者應用花費了大量的時間在內存模型的構建上或者是在UI線程中計算了游戲的下一步動作。要記住:
即便是最高效的代碼也需要花費時間來運行。
任何情況下都不要在UI線程中執行耗時操作,而是要將這些工作放在一個單獨的線程中執行。這可以使UI線程保持流暢工作(UI線程負責驅動用戶界面的事件循環)。
在Android中,應用程序的響應態由Activity Manager及Window Manager負責監控。系統會在偵測到以下狀況時顯示ANR對話框:
對輸入事件在5秒內沒有作出響應。 BroadcastReceiver在10秒內沒有執行完畢。Android應用程序默認運行在UI線程中。這意味著在UI線程中的任何耗時操作都會引發ANR問題,因為這會使應用程序給不到輸入事件或者意圖廣播處理的機會。
因此,在UI線程中的每個方法都應當做盡可能少的工作,尤其是Activity的生命周期回調函數。像網絡或數據庫操作,或者大量的計算之類的耗時操作應當在工作線程中執行。
創建用於執行耗時操作的線程最便捷的方式莫過於使用AsyncTask了。只需要繼承AsyncTask,然後重寫doInBackground()就可以執行了。如果要向用戶展示工作進度,你可以使用publishProgress()方法,它會回調onProgressUpdate()方法(該方法運行於UI線程)。
在onProgressUpdate()內我們可以更新進度條。
private class DownloadFilesTask extends AsyncTask{ // Do the long-running work in here protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize = 0; for (int i = 0; i < count; i++) { totalSize += Downloader.downloadFile(urls[i]); publishProgress((int) ((i / (float) count) * 100)); // Escape early if cancel() is called if (isCancelled()) break; } return totalSize; } // This is called each time you call publishProgress() protected void onProgressUpdate(Integer... progress) { setProgressPercent(progress[0]); } // This is called when doInBackground() is finished protected void onPostExecute(Long result) { showNotification("Downloaded " + result + " bytes"); } }
使用execute()方法啟動工作線程:
new DownloadFilesTask().execute(url1, url2, url3);
如果不采用這種方式,我們還有另一種實現方法:創建自己的Thread或HandlerThread。如果采用這種方法,那麼應該設置該線程的優先級為”background”:通過Process.setThreadPriority()方法及參數THREAD_PRIORITY_BACKGROUND設置。
如果沒有設置該優先級,那麼該線程會使應用感到變慢,因為該線程的優先級默認與UI線程的優先級一致,它們會互相搶占CPU資源。
如果實現了自己的Thread或HandlerThread,那麼要確保在等待其它工作線程完成之前UI線程不被阻塞—不要調用Thread.wait()或Thread.sleep()。如果需要等待其它線程的執行結果,可以為UI線程創建一個Handler。這樣做可以使UI線程還可以對
輸入事件保持響應能力。這樣就可以避免5秒內無響應的ANR對話框出現。
BroadcastReceiver在執行時間上有特殊的限制,這意味著在其內部的工作一定是輕量級的:比如在後台做一些保存設置或者發送通知的工作。所以與UI線程中執行的方法一樣,廣播接收器內也應當杜絕耗時操作的出現。
TIP: 你可以使用StrictMode來發現UI線程中意外出現的耗時操作。
一般來說,100~200毫秒是用戶所能感知到應用卡頓的極限。下面列出了一些可以避免應用程序ANR的一些點,同樣也有助於防止出現卡頓的情況:
如果應用需要對用戶輸入做大量的後台工作,可以顯示一個進度表示工作正在進行。 對於游戲類的復雜計算,應該將這些工作放在工作線程中執行。 如果應用在初始化階段需要花費一些時間,可以考慮顯示一個閃屏頁面或者盡可能快的顯示主界面:展示加載正在進行,並進行異步數據填充。在這些情況下都應當表明任務正在進行,以免讓用戶認為應用已經卡死。 使用Systrace或Traceview等性能工具檢查APP的響應瓶頸。本文實例講述了Android開發之自定義View(視圖)用法。分享給大家供大家參考,具體如下:View類是Android的一個超類,這個類幾乎包含了所有的屏幕類型。每一個
一個安卓開發的朋友發我一個視頻並向詢問我視頻中效果怎麼實現,我當即給他說 ,這個簡單,用幀動畫就可以實現。然後就被他pass掉了,於是我只好祭出plan B。但是我當時沒
一:在Android程序開發中,我們經常會去用到Shape這個東西去定義各種各樣的形狀,首先我們了解一下Shape下面有哪些標簽,都代表什麼意思:(1).solid:填充
xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:a