安卓APP項(xiàng)目開發(fā)怎樣解決ANR異常的處理?深圳APP開發(fā)公司認(rèn)為ANR(ApplicationNotResponding)即“應(yīng)用程序無響應(yīng)”。在Android系統(tǒng)中,如果APP沒有在某個(gè)限定的時(shí)間內(nèi)完成某個(gè)事件或消息的處理,系統(tǒng)會(huì)顯示一個(gè)對(duì)話框,提示用戶APP沒有響應(yīng),用戶可以選擇繼續(xù)等待或者關(guān)閉這個(gè)應(yīng)用程序,如圖21-1所示。
在ActivityManagerService.java中,定義了如下ANR的超時(shí)時(shí)間:
// How long we allow a receiver to run before giving up on it. static final int BROADCAST_ FG_ TIMEOUT = 10* 1000; static final int BROADCAST_ BG_ TIMEOUT = 60* 1000; // How long we wait until we timeout on key dispatching. static final int KEY_ DISPATCHING_ TIMEOUT = 5* 1000;
BROADCAST_FG_TIMEOUT和BROADCAST_BG_TIMEOUT分別對(duì)應(yīng)前臺(tái)廣播和后臺(tái)廣播。目前遇到得比較多的情況是對(duì)按鍵或觸屏操作的處理沒有在5秒內(nèi)完成,此種情況通常發(fā)生在APP的主線程,可以使用簡單記錄數(shù)值的方法,判斷主線程的運(yùn)行狀況。具體實(shí)現(xiàn)方式如下所示。創(chuàng)建一個(gè)Service類,在此Service運(yùn)行的時(shí)候檢測主線程的運(yùn)行狀況,代碼如下:
// How long we wait for a service to finish executing. static final int SERVICE_ TIMEOUT = 20* 1000;
// How long we wait for a service to finish executing. static final int SERVICE_ BACKGROUND_ TIMEOUT = SERVICE_ TIMEOUT * 10
SERVICE_TIMEOUT和SERVICE_BACKGROUND_TIMEOUT分別對(duì)應(yīng)前臺(tái)Service和后臺(tái)Service。SERVICE_TIMEOUT和SERVICE_BACKGROUND_TIMEOUT分別對(duì)應(yīng)前臺(tái)Service和后臺(tái)Service。如果APP沒有在某個(gè)限定的時(shí)間內(nèi)完成某個(gè)事件或消息的處理,系統(tǒng)會(huì)顯示一個(gè)對(duì)話框,提示用戶APP沒有響應(yīng),用戶可以選擇繼續(xù)等待或者關(guān)閉這個(gè)應(yīng)用程序,如圖21-1所示。目前遇到得比較多的情況是對(duì)按鍵或觸屏操作的處理沒有在5秒內(nèi)完成,此種情況通常發(fā)生在APP的主線程,可以使用簡單記錄數(shù)值的方法,判斷主線程的運(yùn)行狀況。具體實(shí)況方式如下所示。創(chuàng)建一個(gè)Service類,在此Service運(yùn)行的時(shí)候檢測主線程的運(yùn)行狀況,代碼如下:
public class ANRService extends Service { private String TAG = "ANRService "; private int workThreadTick = 0; private int mainThreadTick = 0; private boolean flag = true; // 主 線程 ANR 超時(shí) 時(shí)間 private int mainThreadTimeOut = 5000; private Handler mHandler = new Handler(); @ Override public IBinder onBind( Intent intent) { return null; } @ Override public void onCreate() { super. onCreate(); exception();
} private void exception(){ new Thread( new Runnable() { @ Override public void run() { while( flag){ workThreadTick = mainThreadTick; // 向 主線 程 發(fā)送 消息 計(jì)數(shù)器 值 加 1 mHandler. post( tickerRunnable); try { Thread. sleep( mainThreadTimeOut); } catch (InterruptedException e) { e. printStackTrace(); } // 子 線程 在 等待 5 秒 后, 判斷 子 線程 和 主 線程 的 變量 值 是否 相等; 如果 相等, 意味著 主 線程 在 5 秒 內(nèi) 沒有 處理 完 子 線程 發(fā) 的 消息, 發(fā)生了 ANR 異常 if( workThreadTick == mainThreadTick){ flag = false; // 獲取 并 打印 主 線程 的 堆棧 信息
Thread mainThread = Looper. getMainLooper(). getThread(); StackTraceElement[] stackElements = mainThread. getStackTrace(); String stackString = "ANR Exception\ n"; if (stackElements != null) { for (int i = 0; i < stackElements. length; i++) { stackString = stackString + stackElements[ i]. getClassName() + "." + stackElements[ i]. getMethodName() + " (" + stackElements[ i]. getFileName() + ":" + stackElements[ i]. getLineNumber() + ")" + "\n"; } Log. e( TAG, stackString); } } } } }). start(); }
private final Runnable tickerRunnable = new Runnable() { @ Override public void run() { mainThreadTick = (mainThreadTick + 1) % 10; } }; }
在AndroidManifest.xml文件中,增加ANRService類的聲明,代碼如下:
< service android: name=" com. ruwant. eam. service. ANRService"></ service>
在創(chuàng)建MainActivity時(shí)啟動(dòng)ANRService,代碼如下:
@Override protected void onCreate( Bundle savedInstanceState) { super. onCreate( savedInstanceState); setContentView( R. layout. activity_ main); serviceIntent = new Intent( MainActivity. this, ANRService. class); startService( serviceIntent);}
設(shè)置點(diǎn)擊按鈕時(shí),主線程休眠6秒,通過這種方式驗(yàn)證ANRService是否能正常工作,檢測到ANR的發(fā)生。代碼如下:
scanButton = (Button) findViewById( R. id. scan_ button); scanButton. setOnClickListener( new Button. OnClickListener(){ public void onClick( View v){ scanData(); } }); private void scanData(){ Log. e( TAG," scanData"); try { Thread. sleep( 6* 1000); } catch (InterruptedException e) { e. printStackTrace(); } }
運(yùn)行APP,然后點(diǎn)擊按鈕,打印如下Log。
01- 21 15: 23: 56. 543 12233- 12233/ com. ruwant. eam E/ MainActivity: scanData 01- 21 15: 24: 01. 577 12233- 12291/ com. ruwant. eam E/ ANRService: ANR Exception
lang. Thread. sleep( Thread. java:- 2) java. lang. Thread. sleep( Thread. java: 1046) java. lang. Thread. sleep( Thread. java: 1000) com. ruwant. eam. activity. MainActivity. scanData( MainActivity. java: 199) com. ruwant. eam. activity. MainActivity. access$ 400( MainActivity. java: 39) com. ruwant. eam. activity. MainActivity$ 5. onClick (MainActivity. java: 154) android. view. View. performClick( View. java: 5264) android. view. View. View$ PerformClick. run( View. java: 21297) android. os. Handler. handleCallback (Handler. java: 743) android. os. Handler. dispatchMessage (Handler. java: 95) android. os. Looper. loop( Looper. java: 150) android. app. ActivityThread. main( ActivityThread. java: 5546) java. lang. reflect. Method. invoke( Method. java:- 2)
com. android. internal. os. ZygoteInit$ MethodAndArgsCaller. run( ZygoteInit. java: 794) com. android. internal. os. ZygoteInit. main( ZygoteInit. java: 684)
從Log中可以看出,點(diǎn)擊按鈕5秒后,ANRService檢測到了ANR異常,并打印出了發(fā)生異常時(shí)的堆棧信息,其中記錄了發(fā)生異常的類名、方法名和代碼行數(shù)。這樣,就實(shí)現(xiàn)了對(duì)ANR異常的檢測和記錄異常信息,方便分析和解決問題。
APP開發(fā)公司提醒在開發(fā)過程中,對(duì)于可能出現(xiàn)異常的地方盡量用try…catch…捕獲異常,這樣可以針對(duì)不同的異常給用戶顯示不同的提示信息,并對(duì)程序做不同的處理,用戶體驗(yàn)性也比較好。在處理異常的時(shí)候,盡量少重啟APP,以便給用戶良好的用戶體驗(yàn)。也可以使用友盟和OneAPM之類的SDK,其中有捕獲程序崩潰日志,并將其發(fā)送到服務(wù)器的功能。好了,APP開發(fā)公司本文關(guān)于“安卓APP項(xiàng)目開發(fā)怎樣解決ANR異常的處理?”的知識(shí)就分享到這里,謝謝關(guān)注,博納網(wǎng)絡(luò)編輯整理。