避免Android開發中的ANR

來源:互聯網
上載者:User

ANRs (“Application Not Responding”),意思是”應用沒有響應“。

在如下情況下,Android會報出ANR錯誤:

– 主線程 (“事件處理線程” / “UI線程”) 在5秒內沒有響應輸入事件

– BroadcastReceiver 沒有在10秒內完成返回

通常情況下,下面這些做法會導致ANR

1、在主線程內進行網路操作

2、在主線程內進行一些緩慢的磁碟操作(例如執行沒有最佳化過的SQL查詢)

應用應該在5秒或者10秒內響應,否則使用者會覺得“這個應用很垃圾”“爛”“慢”…等等

一些資料(Nexus One為例)

• ~0.04 ms – 通過管道進程從A->B再從B->A寫一個位元組;或者(從dalvik)讀一個簡單的/proc檔案

• ~0.12 ms – 由A->B 再由B->A 進行一次Binder的RPC調用

• ~5-25 ms – 從未緩衝的flash
• ~5-200+(!) ms – 向為緩衝的flash中寫點東西(下面是具體資料)

•    16 ms – 60fps的視頻中的一幀

•    41 ms – 24fps的視頻中的一幀

• 100-200 ms – human perception of slow action

• 108/350/500/800 ms – 3G網路上ping(可變)

• ~1-6+ seconds – 通過HTTP在3G網路上擷取6k的資料

android.os.AsyncTask

AsyncTask 可以與UI線程很方便的配合,這個類可以在後台執行一些操作,並在執行結束的時候將結果發布到UI線程中去,並且無需使用線程或handler來控制。

例子:

private class DownloadFilesTask extends AsyncTask {protected Long doInBackground(URL... urls) {  // on some background threadint count = urls.length;long totalSize = 0;for (int i = 0; i < count; i++) {totalSize += Downloader.downloadFile(urls[i]);publishProgress((int) ((i / (float) count) * 100));}return totalSize;     } protected void onProgressUpdate(Integer... progress) {  // on UI thread!setProgressPercent(progress[0]);} protected void onPostExecute(Long result) {  // on UI thread!showDialog("Downloaded " + result + " bytes");}} new DownloadFilesTask().execute(url1, url2, url3);  // call from UI thread!private boolean handleWebSearchRequest(final ContentResolver cr) {            ...new AsyncTask() {    protected Void doInBackground(Void... unused) {    Browser.updateVisitedHistory(cr, newUrl, false);    Browser.addSearchUrl(cr, newUrl);    return null;    } }.execute()            ...    return true; }
AsyncTask要點

1、必須從主線程調用,或者線程中有Handler或Looper。

2、不要在一個可能會被另外一個AsyncTask調用的庫裡面使用AsyncTask(AsyncTask是不可重新進入的)

3、如果從一個activity中調用,activity進程可能會在AsyncTask結束前退出,例如:

  • 使用者退出了activity
  • 系統記憶體不足
  • 系統暫存了activity的狀態留待後用
  • 系統幹掉了你的線程

如果AsyncTask中的工作很重要,應該使用……

android.app.IntentService

Eclair(2.0, 2.1)文檔中說:

“An abstract Service that serializes the handling of the Intents passed upon service start and handles them on a handler  thread.  To use this class extend it and implement onHandleIntent(Intent). The Service will automatically be  stopped when the last enqueued Intent is handled.”
有點令人困惑,因此…幾乎沒人用

Froyo (2.2) 的文檔, 又澄清了一下….

android.app.IntentService

“IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests  through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself  when it runs out of work.

This ‘work queue processor’ pattern is commonly used to offload tasks from an application’s main thread. The IntentService class exists to  simplify this pattern and take care of the mechanics. To use it, extend IntentService and implement onHandleIntent(Intent). IntentService  will receive the Intents, launch a worker thread, and stop the service as appropriate.

All requests are handled on a single worker thread — they may take as long as necessary (and will not block the application’s main loop), but  only one request will be processed at a time.”

IntentService 的好處
  • Acitivity的進程,當處理Intent的時候,會產生一個對應的Service
  • Android的進程處理器現在會儘可能的不kill掉你
  • 非常容易使用

日曆中IntentService的應用

public class DismissAllAlarmsService extends IntentService {@Override public void onHandleIntent(Intent unusedIntent) {ContentResolver resolver = getContentResolver();...resolver.update(uri, values, selection, null);}}in AlertReceiver extends BroadcastReceiver, onReceive():  (main thread)    Intent intent = new Intent(context, DismissAllAlarmsService.class);    context.startService(intent);
其它技巧

1、當啟動AsyncTask的時候,立刻disable UI元素(按鈕等等)。

2、顯示一些動畫,表示在處理中

3、使用進度條對話方塊

4、使用一個定時器作為耗時警告,在AsyncTask開始時啟動定時器,在AsyncTask的onPostExecute方法中取消定時器。

5、當不確定要耗時多久的時候,組合使用上述所有方法

總結
  • 離開主線程!
  • 磁碟和網路操作不是馬上就能完的
  • 瞭解sqlite在幹嘛
  • 進度展示很好

PS,在視頻講座中,作者還提到,Chrome團隊為了避免Jank(響應逾時而死掉),幾乎所有的功能和任務都會在子線程裡面去做。這一點也值得在Android中借鑒。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.