Android启动页跳转首页偶现Input dispatching timed out ANR
问题根因
你遇到的是典型的输入事件派发超时类ANR,从日志可以先排除内存压力诱因:/proc/pressure/memory 统计项全为0,不存在内存吃紧导致的进程调度阻塞。
核心触发逻辑:SplashActivity跳转首页时,系统需要向SplashActivity的Window派发FocusEvent(hasFocus=false)焦点移除事件,按照Android系统机制,输入事件需要在5s内被主线程消费完成,当时主线程被阻塞超过5004ms没处理该事件,直接触发ANR。
日志里系统Load值达到29+,说明ANR发生时设备CPU负载极高,进程调度延迟比平时高,这也是问题随机出现的核心原因:如果设备空闲,主线程哪怕卡3-4s也可能凑不够超时阈值,赶上CPU满载时,很短的耗时加上调度延迟就会触发ANR。
这类ANR在启动页场景的常见卡点:
- 启动拉取服务端数据的逻辑跑在主线程:包括同步网络请求、大体积返回值的JSON解析、启动数据批量写入数据库/SharedPreferences等重IO/计算逻辑,直接堵死主线程消息队列。
- 生命周期方法塞了重逻辑:SplashActivity的onPause/onStop、或者首页MainActivity的onCreate/onStart/onResume里放了大量SDK初始化、复杂布局渲染、资源解码等耗时操作,焦点派发的消息排在这些耗时任务后面,得不到及时执行。
- 跳转逻辑存在主线程阻塞:比如用CountDownLatch、wait/while循环在主线程同步等待网络请求返回才触发跳转,没有加超时限制,网络差的时候直接把主线程卡死。
- SharedPreferences的同步提交滥用:大量调用
commit()方法写SP,或者频繁apply()导致系统把SP写入任务调度到主线程排队执行。
排查方法
- 先抓ANR现场堆栈:ANR发生时系统会自动把进程堆栈写到
/data/anr/traces.txt文件,直接找主线程的调用栈,看当时主线程卡在哪个方法执行,绝大多数场景可以直接定位到耗时卡点。 - 全链路埋点测耗时:给SplashActivity的onCreate、拉取数据回调、跳转方法、首页onCreate/onStart/onResume各个节点加耗时日志,复现问题后看哪个方法执行时间异常(单方法超过100ms就属于需要优化的重逻辑),尤其是跳转前后执行的逻辑,是重点排查对象。
- 开StrictMode检测:在debug版本打开主线程IO、网络操作检测,只要主线程跑了网络、文件读写等违规操作直接打日志,提前把藏在主线程的耗时操作揪出来,不用等ANR发生再找。
修复方案
- 所有启动阶段的网络请求、数据解析、IO操作全挪到工作线程执行,用协程、线程池做线程切换,主线程只保留UI更新、页面跳转这类轻量操作,绝对不要在主线程做同步等待。
- 拆分启动初始化任务:首页非首屏必须的SDK初始化、预加载逻辑不要全塞首页启动生命周期,可以放到首屏渲染完成后、或者主线程空闲时(通过
Looper.myQueue().addIdleHandler)执行,降低启动阶段主线程压力。 - 给启动阶段的异步等待加超时:比如拉取服务端启动配置,最多等待3s,不管是否拉取成功都要触发跳转,避免极端场景下无限等待堵流程。
- SP操作尽量用
apply()替代commit(),大批量SP写入放到工作线程执行,不要在启动阶段批量写大量SP数据。
内容的提问来源于stack exchange,提问作者Amitanshu Gupta
相关产品推荐
相关产品推荐

