当前位置: 首页 > article >正文

android anr 处理

ANR(Application Not Responding)是 Android 中的一种常见问题。当应用程序未能在规定时间内响应用户输入、完成后台任务或处理系统消息时,系统会弹出一个对话框,提示“应用无响应”。这通常会严重影响用户体验。

在 Android 系统中,ANR 的触发主要有以下几种情境:

应用的主线程长时间阻塞,导致 UI 无法响应用户操作。
应用在处理特定类型的任务(如广播或服务)时未能在系统设定的时间内完成。
本文将结合 ANR 的源码逻辑和常见场景,深入解析 ANR 的三种主要类型及其解决方案。
一、ANR 的三种主要类型
1. Input Dispatching Timeout(输入事件分发超时)
问题描述
系统对用户输入事件(如点击、触摸等)的分发存在时限。默认情况下,主线程需要在 5 秒 内处理输入事件,否则会触发 ANR。
优化布局和绘制性能使用 ViewStub 或延迟加载减少布局复杂度。

2. BroadcastQueue Timeout(广播处理超时)
问题描述
广播接收器必须在指定时间内完成其任务:

前台广播:10 秒。
后台广播:60 秒。
如果超时,系统会认为应用发生了 ANR。
触发条件
在 onReceive() 方法中执行了耗时操作。
使用了复杂的广播逻辑或多次调用网络请求。
减少广播的频繁触发合理设计广播逻辑,避免不必要的广播。
使用 WorkManager 替代广播对于复杂任务,可以考虑使用 WorkManager,支持异步任务调度。

3. Service Timeout(服务处理超时)
问题描述
服务必须在规定时间内完成启动或执行任务:

前台服务:20 秒。
后台服务:200 秒。
触发条件
服务启动时进行复杂的初始化操作。
服务中执行了长时间未完成的任务。

二、ANR 的排查与分析
1. 使用日志定位
在 logcat 中,ANR 相关日志通常以以下关键字开头:

“ANR in”:发生 ANR 的应用包名。
“Reason”:触发 ANR 的原因。
Reason: Input dispatching timed out (App did not respond to an input event within 5.0s)
Reason: Broadcast of Intent { act=android.intent.action.BOOT_COMPLETED }
Reason: executing service com.example.app/.MyService
“Load”:设备负载情况(CPU 使用率等)。
示例:

ANR in com.example.app
PID: 12345
Reason: Input dispatching timed out (App did not respond to an input event within 5.0s)
Load: 5.68 / 4.23 / 2.11

2. Trace 文件分析
trace.txt 文件是 Android 系统在发生 ANR 时自动生成的日志文件,记录了系统中所有线程的堆栈信息,特别是 主线程的状态。通过分析这个文件,开发者可以定位导致 ANR 的根本原因。以下是详细讲解分析 trace.txt 的步骤。

2.1 如何获取 trace.txt 文件
adb pull /data/anr/traces.txt
在 logcat 中标记文件生成路径每次发生 ANR 时,logcat 会记录 trace.txt 的路径。
在调试工具中直接查看部分集成开发环境(如 Android Studio)可以在运行时直接查看 ANR 信息。
2.2 trace.txt 的结构
trace.txt 文件主要包括以下内容:

线程信息每个线程的状态以线程名开头,如:
"main" prio=5 tid=1 Native
1
AI助手
"main":线程名称。主线程通常是 main。
prio=5:线程优先级。
tid=1:线程 ID。
Native/VM:线程运行环境。Native 表示本地代码,VM 表示虚拟机代码。
线程状态紧随线程信息的是其状态,如:
| state=RUNNABLE
1
AI助手
常见状态:

RUNNABLE:线程正在运行或等待 CPU 分配。
WAITING/TIMED_WAITING:线程等待某个条件或超时时间到达。
BLOCKED:线程被阻塞,通常因为锁争用。
堆栈信息每个线程的堆栈信息按调用顺序列出,从最顶层开始,如:
2.3 如何分析主线程的堆栈
定位主线程
主线程通常标识为:

"main" prio=5 tid=1 Native
主线程是 ANR 问题的重点,因为 UI 操作、输入事件、服务启动等都依赖于主线程。如果主线程被长时间阻塞,系统会认为应用无响应。

查找线程状态
主线程的状态直接决定了问题的方向:

RUNNABLE:线程在运行或等待 CPU。原因:可能是计算任务过于耗时或 CPU 资源不足。
WAITING:线程正在等待另一个线程的信号或资源。原因:通常是锁等待或阻塞操作。
BLOCKED:线程正在尝试获取另一个线程持有的锁。原因:锁争用或死锁问题。

分析堆栈信息
从主线程堆栈中,重点关注以下几点:

调用路径是否正常:是否存在循环调用或无意义的深层递归。
方法是否耗时:堆栈中是否包含 I/O 操作、网络请求、大量数据处理等。
第三方库问题:检查堆栈中是否包含第三方库的调用,它们可能引发性能问题。
2.4 示例分析
假设 trace.txt 文件中记录了以下主线程堆栈:

"main" prio=5 tid=1 Native
  | state=WAITING
  at java.lang.Object.wait(Native Method)
  - waiting on <0x12345> (a java.lang.Object)
  at com.example.app.Worker.performTask(Worker.java:50)
  - locked <0x12345> (a java.lang.Object)
  at com.example.app.MainActivity.onButtonClick(MainActivity.java:32)
  at android.view.View.performClick(View.java:7125)
  at android.view.View$PerformClick.run(View.java:28314)
  at android.os.Handler.handleCallback(Handler.java:938)
  at android.os.Handler.dispatchMessage(Handler.java:99)
  at android.os.Looper.loop(Looper.java:268)
  at android.app.ActivityThread.main(ActivityThread.java:7870)
state=WAITING 表明主线程正在等待另一个线程释放资源。
定位阻塞点
java.lang.Object.wait():主线程在等待一个 java.lang.Object 锁(对象 ID 为 <0x12345>)。
锁被 com.example.app.Worker.performTask 方法持有。
问题根源是 Worker.performTask() 中未能及时释放锁。
解决方法:优化 performTask 方法,确保锁释放及时或改用非阻塞式并发工具。
2.5 综合分析多个线程
ANR 问题可能涉及多个线程的交互。例如,主线程等待某个工作线程,而该工作线程又被其他线程阻塞。这种情况下,需要结合其他线程堆栈信息:

示例
"WorkerThread" prio=5 tid=12 Native
  | state=BLOCKED
  at com.example.app.DatabaseHelper.query(DatabaseHelper.java:120)
  - waiting to lock <0x54321&gt> (a java.lang.Object) held by tid=14

继续查找 tid=14 的堆栈信息,找到问题根源。
2.6 常见问题与解决策略
问题类型    表现    解决策略
主线程阻塞    堆栈显示主线程处于 WAITING/BLOCKED    检查锁争用,优化主线程任务逻辑。
后台线程卡死    辅助线程长时间运行,导致主线程等待    使用线程池或优化线程任务分配。
耗时操作未异步化    堆栈中出现 sleep() 或 I/O 操作    将耗时操作移至工作线程。
网络或数据库瓶颈    堆栈中显示网络或数据库方法长时间运行    优化查询逻辑或使用缓存。
3. 使用 Systrace 或 Perfetto
通过 Systrace 或 Perfetto 工具分析应用的线程调度和性能瓶颈,定位主线程阻塞原因。后续文章会详细讲解Perfetto的相关知识。

三、总结
ANR 的本质是主线程未能在规定时间内完成预期任务或响应输入。
常见类型包括输入事件分发超时、广播处理超时和服务启动超时。
解决方案的核心是优化主线程逻辑,将耗时任务移至后台线程,并充分利用 Android 提供的异步工具(如 AsyncTask、HandlerThread 和 WorkManager)。
通过合理设计代码和使用调试工具,开发者可以有效避免和解决 ANR 问题,提升应用性能和用户体验


http://www.kler.cn/a/447640.html

相关文章:

  • 摩尔信使MThings的逻辑控制功能范例
  • 图形学笔记 - 5. 光线追踪2 - 加速结构
  • 【ETCD】【源码阅读】深入分析 storeTxnWrite.Put方法源码
  • Spring(二)---基于注解的方式实现Bean管理和注入属性
  • HUAWEI-eNSP交换机链路聚合(手动负载分担模式)
  • UE5喷涂功能
  • Net9解决Spire.Pdf替换文字后,文件格式乱掉解决方法
  • Git(11)之log显示支持中文
  • 13_HTML5 Audio(音频) --[HTML5 API 学习之旅]
  • 使用R语言高效去除低丰度OTU:从概念到实操
  • Python 写的 智慧记 进销存 辅助 程序 导入导出 excel 可打印
  • 【LuaFramework】服务器模块相关知识
  • 基于BigBangBigCrunch优化(BBBC)的目标函数求解算法matlab仿真
  • 【Rust自学】5.1. 定义并实例化struct
  • AtCoder Beginner Contest 385(A~E)题解
  • OpenEuler22.04配置zookeeper+kafka三节点集群
  • 前端滚动条自定义样式
  • 渗透测试-前后端加密分析之RSA+AES
  • 使用Python实现无人机自动导航系统:探索智能飞行的奥秘
  • ansible剧本快速上手
  • 汽车IVI中控开发入门及进阶(三十八):手机投屏HiCar开发
  • golang rocketmq保证数据一致性(以电商订单为例)
  • JAVA前端开发中type=“danger“和 type=“text“的区别
  • 《计算机组成及汇编语言原理》阅读笔记:p28-p47
  • 修改npm镜像源
  • MyBatis是什么?为什么有全自动ORM框架还是MyBatis比较受欢迎?