ANR出现的几种情况,ANR原因,如何排查ANR、避免ANR
ANR出现的几种情况
主线程在规定时间内未处理完相应工作,就会ANR。
① 输入事件(按键和touch)5s内未被处理;
② BroadcastReceiver的事件,onReceiver方法在规定时间内没处理完(前台广播10s,后台广播60s);
③ service前台20s后台200s未完成启动;
④ ContentProvider的publish在10s内没进行完。
造成ANR的原因
1、在主线程中执行了耗时操作,比如网络读取图片数据并进行图片转换;
2、在主线程中进行IO读写、磁盘读写、数据库读写等操作;
3、在主线程中大量创建新对象;
如何避免ANR
1、在UI线程中不要进行耗时操作;比如在Activity的onCreate()或者onResume()生命周期中不要做耗时操作;
2、创建子线程来执行耗时操作;
3、尽量使用Handler来处理主线程和子线程之间的交互;
4、可以使用AsyncTask来执行异步任务并及时更新UI;
如何排查ANR
1、查看报错的Log日志文件;具体可查看ANR的类型,CPU的使用情况等信息,并不能进行准确定位;
2、分析traces.txt文件;如果发生ANR异常,系统会在/data/anr/目录下生成traces.txt文件,可以通过分析traces.txt文件来查看产生ANR的原因,但前提是手机需要Root获取相应的权限;
3、使用BlockCanary第三方监控组件,BlockCanary可以对主线程进行完全透明的监控,而且如果遇到UI卡顿时能精确输出信息定位到问题所在,不需要像Logcat一样,慢慢去找。
BlockCanary的工作原理:
主要利用了主线程中的消息处理机制,在主线程中ActivityThread会默认创建一个Looper,而Looper会调用loop()方法不断从消息队列MessageQueue取出消息,然后通过dispatchMessage()方法进行消息的处理,通过ActivityThread的源码可以发现在dispatchMessage()方法的前后都有log输出事件,而dispatchMessage()是一次消息的处理过程,我们就可以计算从消息处理开始到消息处理结束的时间,如果这个时间超过了16ms的话,那么就可以认定是发生了UI卡顿现象,进而输出异常日志信息。
BlockCanary输出的信息:
(1)基本信息:安装包标示、机型、api等级、uid、CPU内核数、进程名、内存、版本号等;
(2)耗时信息:实际耗时、主线程时钟耗时、卡顿开始时间和结束时间;
(3)CPU信息:时间段内CPU是否忙,时间段内的系统CPU/应用CPU占比,I/O占CPU使用率;
(4)堆栈信息:发生卡慢前的最近堆栈,可以用来帮助定位卡慢发生的地方和重现路径;