標籤:
在Android上,如果你的應用程式有一段時間響應不夠靈敏,系統會向使用者顯示一個對話方塊,這個對話方塊稱作應用程式無響應(ANR:Application Not Responding)對話方塊。使用者可以選擇“等待”而讓程式繼續運行,也可以選擇“強制關閉”。
所以一個流暢的合理的應用程式中不能出現anr,而讓使用者每次都要處理這個對話方塊。因此,在程式裡對響應效能的設計很重要,這樣系統不會顯示ANR給使用者。預設情況下,在android中Activity的最長執行時間是5秒,BroadcastReceiver的最長執行時間則是10秒。
如何來避免考慮上面的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 ANR產生的原理和如何避免