Android ANR

本文深入探讨了ANR(Application Not Responding)现象,分析了其主要原因包括主线程阻塞、耗时操作及CPU资源竞争,并提供了详细的定位和解决步骤,如使用AsyncTask、Thread或HandlerThread处理耗时任务。

ANR全称:Application Not Responding,即应用程序未响应。

主要原因:

应用程序进程中的主线程响应超时,则会产生ANR

(1)应用程序自身引起的。比如:主线程阻塞、挂起、死循环、执行比较长的耗时操作

(2)其他进程引起的。比如:其他进程对CPU的时间占用率过高,导致应用进程抢不到CPU的时间片。

响应超时体现:

(1)应用程序的主线程对输入事件,5s内没有处理完毕

(2)应用程序主线程在执行BroadcastReceiver的onReceive()函数时,10s内没有处理完毕

(3)应用程序主线程在执行Service的各个生命周期函数时,20s内没有处理完毕

解决步骤:

当发生ANR的时候,ActivityManagerService(AMS)会把ANR信息写到LogCat日志中。我们打开Android Device Monitor查看LogCat日志,主要通过ANRManager、ActivityManager等字段过滤出我们想要的信息,保存到文件。文件主要看以下几条信息:

(1)ANR In (Process Name)【Short Component Name】即ANR发生在哪个进程,哪个包/类里,定位到类。

(2)PID  应用程序进程ID

(3)Reason  ANR发生的原因提示。有:Input dispatching timed out.(输入事件引起的ANR);ExecutingService...(Service执行任务引起的ANR);Broadcast of ...(广播引起的ANR)

(4)Process CPU state  分析各进程的时间占用率,来判断某些进程是否长期占用CPU过高,导致应用进程获取不到足够的CPU处理时间,而发生ANR。比如:各进程总的CPU占用率,用户CPU时间占用率、系统CPU时间占用率、iowaitCPU时间占用率

ANR定位和修正

 

可以通过查看/data/anr/traces.txt查看ANR信息。

根本原因是:主线程被卡了,导致应用在5秒时间未响应用户的输入事件。

很多种ANR错误出现的场景:

1) 主线程当中执行IO/网络操作,容易阻塞。

2) 主线程当中执行了耗时的计算。----自定义控件的时候onDraw方法里面经常这么做。

(同时聊一聊自定义控件的性能优化:在onDraw里面创建对象容易导致内存抖动---绘制动作会大量不断调用,产生大量垃圾对象导致GC很频繁就造成了内存抖动。)内存抖动就容易造成UI出现掉帧卡顿的问题

3) BroadCastReceiver没有在10秒内完成处理。

4) BroadCastReceiver的onReceived代码中也要尽量减少耗时的操作,建议使用IntentService处理。

5) Service执行了耗时的操作,因为service也是在主线程当中执行的,所以耗时操作应该在service里面开启子线程来做。

6) 使用AsyncTask处理耗时的IO等操作。

7) 使用Thread或者HandlerThread时,使用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)或者java.lang.Thread.setPriority(int priority)设置优先级为后台优先级,这样可以让其他的多线程并发消耗CPU的时间会减少,有利于主线程的处理。

8) Activity的onCreate和onResume回调中尽量耗时的操作。

### 分析和解决 Android 应用中的 ANR(Application Not Responding)问题 Android 中的 ANR(Application Not Responding)是指应用程序在一定时间内没有响应用户的输入事件或未能及时完成特定组件的操作,系统会判定为应用无响应,并弹出 ANR 对话框。分析和解决 ANR 问题对于提升应用的稳定性与用户体验至关重要。 #### ANR 的类型与触发机制 ANR 主要有以下几种类型,每种类型的触发时间阈值不同: - **Input Event Timeout(输入事件超时)**:主线程在 5 秒内未响应输入事件,例如点击、滑动等。 - **Broadcast Timeout(广播超时)**:前台广播在 15 秒内未完成,后台广播在 60 秒内未完成。 - **Service Timeout(服务超时)**:前台服务在 20 秒内未完成,后台服务在 200 秒内未完成。 - **ContentProvider Timeout(内容提供者超时)**:在 10 秒内未发布内容提供者。 这些机制确保了系统资源的合理调度和用户体验的流畅性。 #### ANR 日志的获取方法 为了分析 ANR 问题,首先需要获取相关的日志信息: - **实时日志捕获**:使用 `adb logcat -v time | grep "ANR in\|am_anr"` 过滤 ANR 关键词。 - **导出 traces 文件**:通过 `adb pull /data/anr/traces.txt` 获取线程堆栈信息(每次新的 ANR 会覆盖旧文件)。 - **完整系统报告**:使用 `adb bugreport` 获取包含 CPU、内存、I/O 等系统数据的完整报告。 这些日志提供了关于 ANR 发生时的应用状态、线程状态和系统资源使用情况。 #### ANR 的核心分析流程 分析 ANR 日志的流程主要包括以下几个步骤: 1. **确认 ANR 类型**:根据日志中的关键词确定 ANR 的具体类型。 2. **分析 trace 文件**:查看线程堆栈信息,识别主线程是否被阻塞、是否存在锁竞争或 Binder 线程耗尽等问题。 3. **定位根因**:通过分析 trace 文件中的调用栈和线程状态,确定 ANR 的根本原因。 #### ANR 治理方案 治理 ANR 问题需要从多个方面入手: - **透彻理解机制**:掌握 Input、Service、Broadcast 和 Binder 等超时机制,以及系统调度原理。 - **强大的监控体系**:线上平台需要抓取 ANR 事件、主线程堆栈和系统 Traces 文件;线下使用 Systrace、Perfetto、Profiler 和 `adb bugreport` 工具进行分析。 - **精准根因分析**:区分主线程阻塞、Binder 线程耗尽、系统资源瓶颈等问题,利用 Traces 文件分析锁和线程状态是关键突破口。 - **针对性优化**: - **主线程优化**:避免在主线程上执行耗时操作,优化布局和视图层次。 - **Binder 调用优化**:异步化 Binder 调用,优化服务端性能。 - **系统资源优化**:关注 CPU、内存和 I/O 使用情况,避免资源瓶颈。 - **现代化架构**:采用 WorkManager、协程/RxJava、响应式架构和生命周期感知组件,提高应用的响应能力。 - **闭环流程与文化**:设定目标、监控告警、深度分析、有效修复、严格验证、灰度发布、持续复盘和知识沉淀。将稳定性(特别是 ANR 率)作为核心质量指标。 #### 使用工具分析 ANR 问题 - **Android Profiler**:通过 Android Studio 的 Profiler 工具可以实时监控 CPU、内存和网络使用情况,帮助识别 ANR 的潜在原因。 - **StrictMode**:在开发阶段启用 StrictMode 可以检测主线程上的违规操作,如网络请求或数据库操作,从而提前发现可能导致 ANR 的问题。 #### 示例代码:使用 StrictMode 检测主线程违规操作 ```java public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectDiskReads() .penaltyLog() .build()); StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() .detectLeakedSqlLiteObjects() .penaltyLog() .build()); } } ``` 通过上述代码,可以在开发阶段检测主线程上的磁盘读取操作,并记录日志以便优化。 --- #### 相关问题 1. 如何通过 Systrace 工具分析 ANR 问题? 2. Android 中如何优化主线程的性能以避免 ANR? 3. 如何在生产环境中监控和捕获 ANR 事件? 4. Android 中如何处理 Binder 线程耗尽导致的 ANR 问题? 5. 如何通过响应式架构减少 ANR 的发生?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值