Android应用ANR率过高:如何从崩溃报告定位Input dispatching timed out根源?
Android 12/13 ANR(Input dispatching timed out)排查与解决思路
一、定位主线程阻塞根源
- 抓取ANR现场的traces文件:系统触发ANR时会在
/data/anr/traces.txt生成调用栈日志,通过adb pull /data/anr/traces.txt导出。文件会明确显示主线程被哪个任务占用,直接锁定违规代码。 - 启用StrictMode强制检测:在
RunnerActivity的onCreate中添加配置,捕获主线程的磁盘IO(含SQLite操作):
调试阶段只要主线程执行SQL,就会抛出异常或打印详细日志,快速定位问题代码。if (BuildConfig.DEBUG) { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectDiskReads() .detectDiskWrites() .penaltyLog() .penaltyDeath() .build()); }
二、优化SQL查询与任务调度
- 所有SQL操作移至后台线程:用Coroutine(Kotlin)、ExecutorService或WorkManager执行查询,绝对禁止主线程操作数据库。
- 合并批量小查询:将多个独立小查询合并为单条复杂查询(如JOIN、子查询),减少数据库IO次数。
- 优化SQL与索引:用
EXPLAIN QUERY PLAN分析慢查询,给频繁过滤、排序的字段加索引,避免全表扫描。示例:EXPLAIN QUERY SELECT * FROM reports WHERE date BETWEEN ? AND ?; - 控制查询并发数:线程池执行查询时,限制核心线程数(如按CPU核心数设4-8个),避免过多并发引发数据库锁竞争,间接阻塞主线程。
三、Android 12/13适配优化
- 合规使用后台任务:若报告生成依赖后台服务,需申请
POST_NOTIFICATIONS权限,启动服务时调用startForeground()显示通知,避免系统限制任务执行。 - 拆分主线程UI操作:后台查询完成后,若需处理大量数据再渲染UI,采用分页加载、异步解析,避免一次性在主线程处理海量数据导致阻塞。
四、补充日志与监控
- 添加关键节点日志:在数据库操作的入口、出口记录执行时间与SQL语句,结合ANR时间点匹配耗时最长的查询:
Log.d("DB", "Start query: " + sql); long start = System.currentTimeMillis(); Cursor cursor = db.rawQuery(sql, args); long end = System.currentTimeMillis(); Log.d("DB", "Query finished, cost: " + (end - start) + "ms"); - 用Android Studio Profiler监控:实时观察主线程CPU占用、任务队列,测试报告生成时,定位主线程的长时间阻塞任务。
内容的提问来源于stack exchange,提问作者Suresh
相关产品推荐
相关产品推荐

