Android- 性能优化 -ANR- 的原因和解决方案,【一步教学,一步到位
// base/services/core/java/com/android/server/wm/InputMonitor.javapublic long notifyANR(InputApplicationHandle inputApplicationHandle,InputWindowHandle inputWindowHandle, String reason) {// ... 略
if (appWindowToken != null && appWindowToken.appToken != null) {final AppWindowContainerController controller = appWindowToken.getController();final boolean abort = controller != null&& controller.keyDispatchingTimedOut(reason,(windowState != null) ? windowState.mSession.mPid : -1);if (!abort) {return appWindowToken.mInputDispatchingTimeoutNanos;}} else if (windowState != null) {try {// 使用 AMS 的方法 long timeout = ActivityManager.getService().inputDispatchingTimedOut(windowState.mSession.mPid, aboveSystem, reason);if (timeout >= 0) {return timeout * 1000000L; // nanoseconds}} catch (RemoteException ex) {}}return 0; // abort dispatching}
然后回在上述方法调用 AMS 的 inputDispatchingTimedOut() 方法继续处理,并最终在 inputDispatchingTimedOut() 方法中将事件传递给 AppErrors
// base/services/core/java/com/android/server/am/ActivityManagerService.javapublic boolean inputDispatchingTimedOut(final ProcessRecord proc,final ActivityRecord activity, final ActivityRecord parent,final boolean aboveSystem, String reason) {// ...
if (proc != null) {synchronized (this) {if (proc.debugging) {return false;}
if (proc.instr != null) {Bundle info = new Bundle();info.putString("shortMsg", "keyDispatchingTimedOut");info.putString("longMsg", annotation);finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info);return true;}}mHandler.post(new Runnable() {@Overridepublic void run() {// 使用 AppErrors 继续处理 mAppErrors.appNotResponding(proc, activity, parent, aboveSystem, annotation);}});}
return true;}
当事件传递到了 AppErrors 之后,它会借助 Handler 处理消息也就调用了最初的那个方法并弹出对话框。
3、ANR 的解决办法
上面分析了 ANR 的成因和原理,下面我们分析下如何解决 ANR.
1. 使用 adb 导出 ANR 日志并进行分析
发生 ANR 的时候系统会记录 ANR 的信息并将其存储到 /data/anr/traces.txt 文件中(在比较新的系统中会被存储都 /data/anr/anr_* 文件中)。我们可以使用下面的方式来将其导出到电脑中以便对 ANR 产生的原因进行分析:
adb rootadb shell ls /data/anradb pull /data/anr/<filename>
在笔者分析 ANR 的时候使用上述指令尝试导出 ANR 日志的时候都出现了 Permission Denied。此时,你可以将手机 Root 之后导出,或者尝试修改文件的读写权限,或者在开发者模式中选择将日志导出到 sdcard 之后再从 sdcard 将日志发送到电脑端进行查看
2. 使用 DDMS 的 traceview 进行分析
在 AS 中打开 DDMS,或者到 SDK 安装目录的 tools 目录下面使用 monitor.bat 打开 DDMS。
TraceView 工具的使用可以参考这篇文章:《Android 性能分析之TraceView使用(应用耗时分析)》
这种定位 ANR 的思路是:使用 TraceView 来通过耗时方法调用的信息定位耗时操作的位置。
资料:
3. 使用开源项目 ANR-WatchDog 来检測 ANR
项目地址是?Github-ANR-WatchDog
该项目的实现原理:创建一个检测线程,该线程不断往 UI 线程 post 一个任务,然后睡眠固定时间,等该线程又一次起来后检測之前 post 的任务是否运行了,假设任务未被运行,则生成 ANRError,并终止进程。
4. 常见的 ANR 场景
I/O 阻塞网络阻塞多线程死锁由于响应式编程等导致的方法死循环由于某个业务逻辑执行的时间太长 5. 避免 ANR 的方法
评论