Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android ANR產生的原因及如何避免

Android ANR產生的原因及如何避免

編輯:關於Android編程

在Android上,如果你的應用程序有一段時間響應不夠靈敏,系統會向用戶顯示一個對話框,這個對話框稱作應用程序無響應(ANR:Application Not Responding)對話框。用戶可以選擇“等待”而讓程序繼續運行,也可以選擇“強制關閉”。所以一個流暢的合理的應用程序中不能出現anr,而讓用戶每次都要處理這個對話框。因此,在程序裡對響應性能的設計很重要,這樣系統不會顯示ANR給用戶。默認情況下,在android中Activity的最長執行時間是5秒,BroadcastReceiver的最長執行時間則是10秒。

ANR 定義

ANR(Application Not Responding)定義 在Android上,如果你的應用程序有一段時間響應不夠靈敏,系統會向用戶顯示一個對話框,這個對話框稱作應用程序無響應(ANR:Application Not Responding)對話框。用戶可以選擇“等待”而讓程序繼續運行,也可以選擇“強制關閉”。所以一個流暢的合理的應用程序中不能出現anr,而讓用戶每次都要處理這個對話框。因此,在程序裡對響應性能的設計很重要,這樣系統不會顯示ANR給用戶。默認情況下,在android中Activity的最長執行時間是5秒,BroadcastReceiver的最長執行時間則
是10秒。

產生原因:由於主線程有很多重要事情要做,比如響應點擊事件等。如果在主線程裡做了太多耗時的操作,則有可能引發ANR。

如果你想模擬的話,比如在主線程裡讓主線程休眠6秒以上。Thread.sleep(6000);則會引發此狀況。所以在4.0以上版本,如果在主線程裡進行網絡訪問的操作,則會報錯。

避免:盡量將耗時的操作放在子線程裡。

產生原因:由於主線程有很多重要事情要做,比如響應點擊事件等。如果在主線程裡做了太多耗時的操作,則有可能引發ANR。

如果你想模擬的話,比如在主線程裡讓主線程休眠6秒以上。Thread.sleep(6000);則會引發此狀況。所以在4.0以上版本,如果在主線程裡進行網絡訪問的操作,則會報錯。

避免:盡量將耗時的操作放在子線程裡。

產生原因:由於主線程有很多重要事情要做,比如響應點擊事件等。如果在主線程裡做了太多耗時的操作,則有可能引發ANR。

如果你想模擬的話,比如在主線程裡讓主線程休眠6秒以上。Thread.sleep(6000);則會引發此狀況。所以在4.0以上版本,如果在主線程裡進行網絡訪問的操作,則會報錯。

避免:盡量將耗時的操作放在子線程裡。

產生原因:由於主線程有很多重要事情要做,比如響應點擊事件等。如果在主線程裡做了太多耗時的操作,則有可能引發ANR。

如果你想模擬的話,比如在主線程裡讓主線程休眠6秒以上。Thread.sleep(6000);則會引發此狀況。所以在4.0以上版本,如果在主線程裡進行網絡訪問的操作,則會報錯。

避免:盡量將耗時的操作放在子線程裡。

產生原因:由於主線程有很多重要事情要做,比如響應點擊事件等。如果在主線程裡做了太多耗時的操作,則有可能引發ANR。

如果你想模擬的話,比如在主線程裡讓主線程休眠6秒以上。Thread.sleep(6000);則會引發此狀況。所以在4.0以上版本,如果在主線程裡進行網絡訪問的操作,則會報錯。

避免:盡量將耗時的操作放在子線程裡。


如何來避免:

考慮上面的ANR定義,讓我們來研究一下為什麼它會在Android應用程序裡發生和如何最佳構建應用程序來避免ANR。 Android應用程序通常是運行在一個單獨的線程(例如,main)裡。這意味著你的應用程序所做的事情如果在主線程裡占用了太長的時間的話,就會引發ANR對話框,因為你的應用程序並沒有給自己機會來處理輸入事件或者Intent廣播。 因此,運行在主線程裡的任何方法都盡可能少做事情。特別是,Activity應該在它的關鍵生命周期方法(如onCreate()和onResume())裡盡可能少的去做創建操作。潛在的耗時操作,例如網絡或數據庫操作,或者高耗時的計算如改變位圖尺寸,應該在子線程裡(或者以數據庫操作為例,通過異步請求的方式)來完成。然而,不是說你的主線程阻塞在那裡等待子線程的完成——也不是調用Thread.wait()或是Thread.sleep()。替代的方法是,主線程應該為子線程提供一個Handler,以便完成時能夠提交給主線程。以這種方式設計你的應用程序,將能保證你的主線程保持對輸入的響應性並能避免由於5秒輸入事件的超時引發的ANR對話框。這種做法應該在其它顯示UI的線程裡效仿,因為它們都受相同的超時影響。 IntentReceiver執行時間的特殊限制意味著它應該做:在後台裡做小的、瑣碎的工作如保存設定或者注冊一個Notification。和在主線程裡調用的其它方法一樣,應用程序應該避免在BroadcastReceiver裡做耗時的操作或計算。但不再是在子線程裡做這些任務(因為BroadcastReceiver的生命周期短),替代的是,如果響應Intent廣播需要執行一個耗時的動作的話,應用程序應該啟動一個Service。順便提及一句,你也應該避免在Intent Receiver裡啟動一個Activity,因為它會創建一個新的畫面,並從當前用戶正在運行的程序上搶奪焦點。如果你的應用程序在響應Intent廣播時需要向用戶展示什麼,你應該使用Notification Manager來實現。 一般來說,在應用程序裡,100到200ms是用戶能感知阻滯的時間阈值。因此,這裡有一些額外的技巧來避免ANR,並有助於讓你的應用程序看起來有響應性。 如果你的應用程序為響應用戶輸入正在後台工作的話,可以顯示工作的進度(ProgressBar和ProgressDialog對這種情況來說很有用)。 特別是游戲,在子線程裡做移動的計算。 如果你的應用程序有一個耗時的初始化過程的話,考慮可以顯示一個Splash Screen或者快速顯示主畫面並異步來填充這些信息。在這兩種情況下,你都應該顯示正在進行的進度,以免用戶認為應用程序被凍結了。

在Android中,Activity Manager 和 Window Manager system services 會監控每個程序的運行,當程序出現如下三種種情況的時候就會彈出ANR的提示對話框: 1.用戶在進行了一種操作後5秒鐘沒有響應。 2.broadCastReceiver所進行的操作在10秒內沒有完成。 3.Service在20秒內沒返回結果。

在APP運行中,出現了ANR是非常讓人惱火的,會帶來非常差的用戶體驗。所以在設計Android應用程序的時候要盡可能的避免產生ANR。那麼如何才能避免ANR的產生呢?只要注意好以下三點,其實很簡單:

1.避免在主線程上進行復雜耗時的操作,比如說發送接收網絡數據/進行大量計算/操作數據庫/讀寫文件等。這個可以通過使用AsyncTask或者使用多線程來實現。

2.broadCastReceiver 要進行復雜操作的的時候,可以在onReceive()方法中啟動一個Service來處理 3.在設計及代碼編寫階段避免出現出現同步/死鎖或者錯誤處理不恰當等情況

ANR是個什麼玩意

 

ANR,是“ApplicationNotResponding”的縮寫,即“應用程序無響應”。系統會向用戶顯示一個對話框,用戶可以選擇“等待”而讓程序繼續運行,也可以選擇“強制關閉”。

在Android中,應用程序的響應是由ActivityManager和WindowManager系統服務監視的。當它監測到A、B、C情況中的一個時,Android就會針對特定的應用程序顯示ANR:

A.在5秒內沒有響應輸入的事件(例如,按鍵按下,屏幕觸摸)--主要類型

B.BroadcastReceiver在10秒內沒有執行完畢

C.Service在特定時間內(20秒內)無法處理完成--小概率類型

造成ABC的原因有很多,比如在主線程中做了非常耗時的操作,如下載,io異常等。還需要注意的是產生這種ANR的前提是要有輸入事件,如果用戶沒有觸發任何輸入事件,即便是主線程阻塞了,也不會產生ANR,因為InputDispatcher沒有分發事件給應用程序,當然也不會檢測處理超時和報告ANR了。

1.如何分析ANR

ANR發生時都會在log中輸出錯誤信息,從log中可以獲得ANR的類型,CPU的使用情況,CPU使用率過高有可能是CPU饑餓導致了ANR。CPU使用率過低說明主線程被block了,如果IOwait高是因為主線程進行I/O操作造成的。

除了log輸出外,你會發現各個應用進程和系統進程的函數堆棧信息都輸出到了一個/data/anr/traces.txt的文件中,這個文件是分析ANR原因的關鍵文件.要獲取到該文件可使用adb指令進行賦權後拉出查看調用stack。通過log、trace.text、代碼結合分析ANR的成因(iowait?Memoryleak?Block?)

2.怎麼避免ANR

要避免問題的產生,就要抓住問題產生的原因(ABC三種):

(1)避免在主線程上進行復雜耗時的操作,比如說發送接收網絡數據/進行大量計算/操作數據庫/讀寫文件等。這個可以通過使用AsyncTask或者使用多線程來實現。

(2)broadCastReceiver要進行復雜操作的的時候,可以在onReceive()方法中啟動一個Service來處理

(3)在設計及代碼編寫階段避免出現出現同步/死鎖或者錯誤處理不恰當等情況。

該文章只是簡單概括介紹ANR,具體的問題處理還是要在開發中去積累,萬變不離其宗掌握方法手到擒來。歡迎大牛指正交流。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved