ANR的一些解决

本文介绍了Android应用程序中的ANR(Application Not Responding)问题,包括ANR的三种类型、导致ANR的原因以及如何避免ANR的方法。文章还详细讨论了如何通过使用AsyncTask和Handler来处理耗时操作,以提高应用程序的响应速度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在Android里, App的响应能力是由Activity Manager和Window Manager系统服务来监控的. 在主线程(UI线程)里面做了太多的阻塞耗时操作, 例如文件读写, 数据库读写, 网络查询等等.

ANR一般有三种类型
1. KeyDispatchTimeout(5 seconds) –主要是类型按键或触摸事件在特定时间内无响应
2. BroadcastTimeout(10 seconds) –BroadcastReceiver在特定时间内无法处理完成
3. ServiceTimeout(20 secends) –小概率事件 Service在特定的时间内无法处理完成

哪些操作会导致ANR 在主线程执行以下操作:
1. 高耗时的操作,如图像变换
2. 磁盘读写,数据库读写操作
3. 大量的创建新对象

3、如何避免
不要在主线程(UI线程)里面做繁重的操作.

  1. UI线程尽量只做跟UI相关的工作
  2. 耗时的操作(比如数据库操作,I/O,连接网络或者别的有可能阻塞UI线程的操作)把它放在单独的线程处理
  3. 尽量用Handler来处理UIThread和别的Thread之间的交互
    4、解决的逻辑
  4. 使用AsyncTask
    a. 在doInBackground()方法中执行耗时操作
    b. 在onPostExecuted()更新UI
  5. 使用Handler实现异步任务
    a. 在子线程中处理耗时操作
    b. 处理完成之后,通过handler.sendMessage()传递处理结果
    c. 在handler的handleMessage()方法中更新UI
    d. 或者使用handler.post()方法将消息放到Looper中

3.1 哪些地方是执行在主线程的
1. Activity的所有生命周期回调都是执行在主线程的.
2. Service默认是执行在主线程的.
3. BroadcastReceiver的onReceive回调是执行在主线程的.
4. 没有使用子线程的looper的Handler的handleMessage, post(Runnable)是执行在主线程的.
5. AsyncTask的回调中除了doInBackground, 其他都是执行在主线程的.
6. View的post(Runnable)是执行在主线程的.


● 主线程被IO操作(从4.0之后网络IO不允许在主线程中)阻塞。
● 主线程中存在耗时的计算
● 主线程中错误的操作,比如Thread.wait或者Thread.sleep等 Android系统会监控程序的响应状况,一旦出现下面两种情况,则弹出ANR对话框
● 应用在5秒内未响应用户的输入事件(如按键或者触摸)
● BroadcastReceiver未在10秒内完成相关的处理
● Service在特定的时间内无法处理完成 20秒
● 使用AsyncTask处理耗时IO操作。
● 使用Thread或者HandlerThread时,调用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)设置优先级,否则仍然会降低程序响应,因为默认Thread的优先级和主线程相同。
● 使用Handler处理工作线程结果,而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程。
● Activity的onCreate和onResume回调中尽量避免耗时的代码
● BroadcastReceiver中onReceive代码也要尽量减少耗时,建议使用IntentService处理。

### Android ANR 解决方案与处理流程 #### 1. ANR 的定义及产生原因 ANR 是指应用程序未响应,通常是因为主线程被阻塞导致无法及时响应用户输入或消息广播。Android 系统对一些操作有严格的时间限制,例如输入事件处理、广播接收等,如果在规定时间内没有得到处理,就会触发 ANR[^1]。 #### 2. 常见的 ANR 类型 - **输入事件分发超时**:当主线程在 5 秒内未能完成输入事件的处理时,会触发 ANR。 - **广播处理超时**:当主线程在 10 秒内未能完成广播接收器的任务时,会触发 ANR。 - **服务启动超时**:当主线程在 20 秒内未能完成服务的启动任务时,会触发 ANR[^2]。 #### 3. ANR解决方法 ##### 优化主线程逻辑 将耗时任务移至后台线程解决 ANR 的关键。可以通过以下方式实现: - **AsyncTask**:适用于简单的异步任务,但需要注意其生命周期问题。 - **HandlerThread**:提供一个带有 Looper 的线程,适合需要频繁通信的任务。 - **WorkManager**:用于执行延迟或周期性任务,特别适合需要保证任务执行的任务[^2]。 ##### 使用调试工具分析 ANR trace.txt 文件是 Android 系统在发生 ANR 时自动生成的日志文件,记录了系统中所有线程的堆栈信息,特别是主线程的状态。通过分析这个文件,可以定位导致 ANR 的根本原因[^3]。 ###### 获取 trace.txt 文件 从设备中提取使用 ADB 命令获取 ANR 堆栈: ```bash adb pull /data/anr/traces.txt ``` 在 logcat 中标记文件生成路径每次发生 ANR 时,logcat 会记录 trace.txt 的路径。在调试工具中直接查看部分集成开发环境(如 Android Studio)可以在运行时直接查看 ANR 信息。 ###### 分析 trace.txt 的结构 trace.txt 文件包含所有线程的堆栈信息,开发者可以通过查找主线程的状态来确定阻塞的原因。例如,如果主线程处于 `wait` 或 `sleep` 状态,可能是因为某个耗时操作未被移至后台线程[^3]。 #### 4. 避免 ANR 的最佳实践 - **减少主线程负担**:确保主线程只处理 UI 更新和轻量级任务,避免执行耗时操作。 - **合理使用线程池**:通过线程池管理后台任务,避免创建过多线程导致资源耗尽。 - **监控应用性能**:使用工具如 Systrace 和 StrictMode 监控应用性能,及时发现潜在问题[^1]。 #### 5. 示例代码 以下是一个将耗时任务移至后台线程的示例: ```java new Thread(() -> { // 耗时操作 try { Thread.sleep(5000); // 模拟耗时任务 } catch (InterruptedException e) { e.printStackTrace(); } runOnUiThread(() -> { // 更新 UI textView.setText("Task Completed"); }); }).start(); ``` #### 6. 总结 通过优化主线程逻辑、使用调试工具分析 ANR 并遵循最佳实践,开发者可以有效避免和解决 ANR 问题,提升应用性能和用户体验[^2]。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值