安卓APP项目开发怎样解决ANR异常的处理?深圳APP开发公司认为ANR(ApplicationNotResponding)即“应用程序无响应”。在Android系统中,如果APP没有在某个限定的时间内完成某个事件或消息的处理,系统会显示一个对话框,提示用户APP没有响应,用户可以选择继续等待或者关闭这个应用程序,如图21-1所示。
在ActivityManagerService.java中,定义了如下ANR的超时时间:
// 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分别对应前台广播和后台广播。目前遇到得比较多的情况是对按键或触屏操作的处理没有在5秒内完成,此种情况通常发生在APP的主线程,可以使用简单记录数值的方法,判断主线程的运行状况。具体实现方式如下所示。创建一个Service类,在此Service运行的时候检测主线程的运行状况,代码如下:
// 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分别对应前台Service和后台Service。SERVICE_TIMEOUT和SERVICE_BACKGROUND_TIMEOUT分别对应前台Service和后台Service。如果APP没有在某个限定的时间内完成某个事件或消息的处理,系统会显示一个对话框,提示用户APP没有响应,用户可以选择继续等待或者关闭这个应用程序,如图21-1所示。目前遇到得比较多的情况是对按键或触屏操作的处理没有在5秒内完成,此种情况通常发生在APP的主线程,可以使用简单记录数值的方法,判断主线程的运行状况。具体实况方式如下所示。创建一个Service类,在此Service运行的时候检测主线程的运行状况,代码如下:
public class ANRService extends Service { private String TAG = "ANRService "; private int workThreadTick = 0; private int mainThreadTick = 0; private boolean flag = true; // 主 线程 ANR 超时 时间 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; // 向 主线 程 发送 消息 计数器 值 加 1 mHandler. post( tickerRunnable); try { Thread. sleep( mainThreadTimeOut); } catch (InterruptedException e) { e. printStackTrace(); } // 子 线程 在 等待 5 秒 后, 判断 子 线程 和 主 线程 的 变量 值 是否 相等; 如果 相等, 意味着 主 线程 在 5 秒 内 没有 处理 完 子 线程 发 的 消息, 发生了 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>
在创建MainActivity时启动ANRService,代码如下:
@Override protected void onCreate( Bundle savedInstanceState) { super. onCreate( savedInstanceState); setContentView( R. layout. activity_ main); serviceIntent = new Intent( MainActivity. this, ANRService. class); startService( serviceIntent);}
设置点击按钮时,主线程休眠6秒,通过这种方式验证ANRService是否能正常工作,检测到ANR的发生。代码如下:
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(); } }
运行APP,然后点击按钮,打印如下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中可以看出,点击按钮5秒后,ANRService检测到了ANR异常,并打印出了发生异常时的堆栈信息,其中记录了发生异常的类名、方法名和代码行数。这样,就实现了对ANR异常的检测和记录异常信息,方便分析和解决问题。
APP开发公司提醒在开发过程中,对于可能出现异常的地方尽量用try…catch…捕获异常,这样可以针对不同的异常给用户显示不同的提示信息,并对程序做不同的处理,用户体验性也比较好。在处理异常的时候,尽量少重启APP,以便给用户良好的用户体验。也可以使用友盟和OneAPM之类的SDK,其中有捕获程序崩溃日志,并将其发送到服务器的功能。好了,APP开发公司本文关于“安卓APP项目开发怎样解决ANR异常的处理?”的知识就分享到这里,谢谢关注,博纳网络编辑整理。