前言
Android发生ANR的情况主要包括输入调度超时、广播超时、服务超时等,解决ANR问题的方法包括避免在主线程进行耗时操作、导出ANR日志信息、分析系统资源信息、查看主线程状态等。
Android系统中,ANR(Application Not Responding)是一种自我保护措施,当主线程出现卡顿时,系统会给用户一个弹出提示,让用户选择继续等待或强制关闭应用。
一、ANR的发生通常与以下几种情况
1.输入调度超时
典型报错日志
Input dispatching timedout(Waitingtosend non-key event because the touched window has not finished processing certain input events that were deliveredtoit earlier.Wait queue length:xx.Wait queue head age:xxxms)如果应用在5秒内未响应输入事件(如按键或屏幕触摸),就会发生ANR。这通常是由于主线程上的问题导致的,如主线程上的阻塞操作或长时间等待获取锁。为了避免这种情况,应避免在主线程上执行阻塞操作或长时间运行的操作,并尽量减少主线程与其他线程之间的锁争用。
原理讲解
输入事件已经成功分发到了你的 App 的焦点窗口,但主线程被耗时操作阻塞:
连续的触摸 / 滑动事件堆积在系统等待队列里,主线程没法及时处理上一轮触摸事件;
队列堆积超时后,系统判定应用输入无响应,触发 ANR。
常见诱因
主线程做网络请求、大文件 IO、复杂布局渲染、同步数据库查询、死循环等耗时操作。
2.广播超时
典型报错日志
Broadcast of Intent{act=xxx flg=xxx(has extras)}原理讲解
广播接收器BroadcastReceiver的onReceive()运行在主线程,系统对广播有严格超时限制:
普通静态广播:onReceive()执行超过10 秒触发 ANR;
有序广播、前台广播超时阈值会更短。
onReceive执行结束后系统就会回收接收器,不能开子线程做耗时任务,子线程也无法延长广播生命周期。
常见诱因
在onReceive里做本地数据库批量写入、同步网络请求、复杂文件处理,或者频繁发送有序广播造成队列堆积。
如果BroadcastReceiver的onReceive()方法执行时间超过规定阈值(通常是10秒),也会触发ANR。解决这一问题的方法包括优化广播接收器的逻辑,确保其执行时间在可接受范围内。
前台广播超时时间是10s,后台广播超时时间是60s。
3.服务超时
分两种场景的日志 & 说明
1.前台 / 后台 Service 启动超时(startService触发)
典型日志
Timeout executing service:ServiceRecord{xxxx u0 xxx.xxx/.XXXService}规则:onCreate()、onStartCommand()主线程执行超过20 秒触发 ANR。
2.绑定 Service 超时(bindService触发)
典型日志
Timeout waitingforservice xxx.xxx/.XXXServicetoconnect规则:onBind()主线程执行超过20 秒触发 ANR。
原理讲解
Service 生命周期全部运行在主线程,如果你在onCreate/onStartCommand/onBind里写了大量同步耗时逻辑,系统在规定时间内收不到 Service 就绪的回调,就会判定超时 ANR。
常见诱因
Service 里直接做文件解压、批量数据迁移、同步网络请求、大量初始化逻辑。
4.没有焦点窗口导致输入超时
典型报错日志
Reason:Input dispatching timedout(Application does not have a ffocused window)原理讲解
Android 系统InputDispatcher负责把触摸、按键等输入事件分发到当前获得焦点的窗口:
你的 App 所有窗口(Activity、Dialog、悬浮窗、插件弹窗等)都没拿到系统焦点,系统找不到输入事件的接收目标;
持续等待 5 秒(默认超时阈值)仍无可用焦点窗口,触发 ANR。
常见诱因
悬浮窗 / 状态栏插件默认加了FLAG_NOT_FOCUSABLE禁止获取焦点、Activity 退到后台被其他应用抢占焦点、页面销毁后新窗口未完成焦点申请。
二、解决ANR问题的方法
- 导出ANR日志信息:当ANR发生时,系统会收集相关日志信息,包括CPU使用情况、线程执行情况等,这些信息可以帮助定位问题原因。
- 分析系统资源信息:关注CPU、内存、IO等系统资源的使用情况,这些信息有助于判断ANR是否由系统资源争抢导致。
- 查看主线程状态:检查主线程是否存在耗时、死锁、等待锁等问题,这些问题可能导致ANR。
结合应用日志、代码或源码分析:通过查看应用日志和代码,可以分析ANR问题发生前应用是否有异常,从而找到具体问题所在。
如果你想快速定位就搜索main关键字,然后看堆栈分析即可!!
综上所述,解决Android的ANR问题需要从避免在主线程进行耗时操作、优化代码逻辑、及时处理系统资源争抢等多个方面入手,同时通过导出和分析ANR日志信息来定位和解决问题