Android ANR详解
ANR(Application Not Responding)是Android系统中当应用程序在特定时间内无法响应用户输入或广播时的错误状态。
ANR的触发条件
| 类型 | 触发条件 | 时间限制 |
|---|---|---|
| 输入事件ANR | 按键或触摸事件未响应 | 5秒 |
| BroadcastReceiver ANR | onReceive()执行超时 | 前台10秒,后台60秒 |
| Service ANR | Service生命周期方法执行超时 | 20秒 |
| ContentProvider ANR | ContentProvider操作超时 | 10秒 |
ANR产生的原因
1. 主线程耗时操作
- 网络请求在主线程执行
- 大量数据库操作
- 复杂的计算任务
- 加载大文件或图片
2. 死锁
- 主线程等待子线程释放锁
- 子线程又等待主线程释放锁
3. 内存不足
- 系统资源紧张
- 频繁GC导致卡顿
4. Binder通信超时
- 跨进程调用超时
- 服务端进程无响应
ANR的定位方法
1. 查看Logcat日志
shellE/ActivityManager: ANR in com.example.app E/ActivityManager: Reason: Input dispatching timed out
2. 分析traces.txt文件
shell/data/anr/traces.txt
包含:
- 所有线程的堆栈信息
- ANR发生的时间点
- 阻塞的代码位置
3. 使用Android Studio Profiler
- CPU Profiler查看主线程状态
- 识别耗时方法
4. StrictMode检测
javaStrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectDiskReads() .detectDiskWrites() .detectNetwork() .penaltyLog() .build());
ANR的解决方案
1. 异步处理耗时操作
java// 使用AsyncTask(已废弃,建议使用其他方式) // 使用线程池 ExecutorService executor = Executors.newFixedThreadPool(4); executor.execute(() -> { // 耗时操作 }); // 使用Kotlin协程 lifecycleScope.launch(Dispatchers.IO) { // 耗时操作 }
2. 使用HandlerThread
javaHandlerThread handlerThread = new HandlerThread("background"); handlerThread.start(); Handler backgroundHandler = new Handler(handlerThread.getLooper());
3. 优化数据库操作
- 使用事务批量操作
- 建立合适的索引
- 避免主线程查询大量数据
4. 避免死锁
- 统一锁的获取顺序
- 使用tryLock()替代lock()
- 减少锁的持有时间
面试要点
- ANR是系统保护机制,不是崩溃
- traces.txt是定位ANR的关键
- 主线程不能执行耗时操作
- 使用Systrace分析性能问题
- 关注卡顿监控和线上ANR收集