Android ANR

到底Android ANR是什么呢? 其实ANR就是Application Not Responding的全称,当某个应用处于长期假死状态时Android系统会弹出一个窗口上面写道,XXX is not responding给出两个按钮一个为force close一个为wait。

        可能会存在这样的情况,你写的代码通过了世界上所有的性能测试,但当用户尝试使用你的应用程序时,仍然让用户感到不爽。应用程序响应不够灵敏的地方包括——反映迟钝,挂起或冻结很长时间,或者需要花费很长的时间来处理输入。

        在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(ANR:Application Not Responding)对话框。用户可以选择让程序继续运行,但是,他们在使用你的应用程序时,并不希望每次都要处理这个对话框。因此,在程序里对响应性能的设计很重要,这样,系统不会显示ANR给用户。

        一般说来,如果应用程序不能响应用户输入的话,系统会显示一个ANR。例如,一个应用程序阻塞在一些I/O操作上(通常是网络访问),这时,应用程序的主线程就不能再处理用户的输入事件。经过一定的时间后,系统认为应用程序已经挂起,并显示ANR来让用户选择杀死应用程序。

        相似地,如果你的应用程序花费太多的时间来构建详细的内存结构,或者也许是在游戏里花费太多时间来计算下一步移动,这时,系统会认为你的应用程序已经挂起。因此,确保这些计算是高效的往往很重要,但即使是最高效的代码仍然需要花费时间来运行。

        在这两种情况下,解决的方法通常是创建一个子线程,然后在线程里做你的大部分工作。这能让主线程(驱动UI事件循环)保持运行,并阻止系统认为你的代码已经冻结。因为这些线程通常是在类级别上完成的,因此,你可以认为响应性能问题是一个类的问题。(与基本性能相比而言,基本性能问题认为是方法级别的问题)

       1 什么引发了ANR?

       在Android里,应用程序的响应性是由Activity Manager和Window Manager系统服务监视的。当它监测到以下情况中的一个时,Android就会针对特定的应用程序显示ANR:

在5秒内没有响应输入的事件(例如,按键按下,屏幕触摸)
BroadcastReceiver在10秒内没有执行完毕

         2 如何避免ANR?

         考虑上面的ANR定义,让我们来研究一下为什么它会在Android应用程序里发生和如何最佳构建应用程序来避免ANR。

Android应用程序通常是运行在一个单独的线程(例如,main)里。这意味着你的应用程序所做的事情如果在主线程里占用了太长的时间的话,就会引发ANR对话框,因为你的应用程序并没有给自己机会来处理输入事件或者Intent广播。

        因此,运行在主线程里的任何方法都尽可能少做事情。特别是,Activity应该在它的关键生命周期方法(如onCreate()和onResume())里尽可能少的去做创建操作。潜在的耗时操作,例如网络或数据库操作,或者高耗时的计算如改变位图尺寸,应该在子线程里(或者以数据库操作为例,通过异步请求的方式)来完成。然而,不是说你的主线程阻塞在那里等待子线程的完成——也不是调用Thread.wait()或是Thread.sleep()。替代的方法是,主线程应该为子线程提供一个Handler,以便完成时能够提交给主线程。以这种方式设计你的应用程序,将能保证你的主线程保持对输入的响应性并能避免由于5秒输入事件的超时引发的ANR对话框。这种做法应该在其它显示UI的线程里效仿,因为它们都受相同的超时影响。

        IntentReceiver执行时间的特殊限制意味着它应该做:在后台里做小的、琐碎的工作如保存设定或者注册一个Notification。和在主线程里调用的其它方法一样,应用程序应该避免在BroadcastReceiver里做耗时的操作或计算。但不再是在子线程里做这些任务(因为BroadcastReceiver的生命周期短),替代的是,如果响应Intent广播需要执行一个耗时的动作的话,应用程序应该启动一个Service。顺便提及一句,你也应该避免在Intent Receiver里启动一个Activity,因为它会创建一个新的画面,并从当前用户正在运行的程序上抢夺焦点。如果你的应用程序在响应Intent广播时需要向用户展示什么,你应该使用Notification Manager来实现。

         3增强响应灵敏性

        一般来说,在应用程序里,100到200ms是用户能感知阻滞的时间阈值。因此,这里有一些额外的技巧来避免ANR,并有助于让你的应用程序看起来有响应性。

         如果你的应用程序为响应用户输入正在后台工作的话,可以显示工作的进度(ProgressBar和ProgressDialog对这种情况来说很有用)。
特别是游戏,在子线程里做移动的计算。

        如果你的应用程序有一个耗时的初始化过程的话,考虑可以显示一个Splash Screen或者快速显示主画面并异步来填充这些信息。在这两种情况下,你都应该显示正在进行的进度,以免用户认为应用程序被冻结了。

 

 

 

### ANR 的原因 在 Android 应用程序中,ANR 错误通常发生在主线程被阻塞的情况下。如果某个线程占用单一线程时间过长(超过 5 秒),这会阻止用户交互并触发系统的 ANR 警告[^1]。 具体来说,当应用程序未能及时响应输入事件或广播接收器超时未完成处理时,系统就会判定该应用无响应,并向用户显示 ANR 对话框。常见的场景包括长时间运行的操作直接放置于主线程上执行,例如网络请求、数据库查询或其他耗时操作。 --- ### 解决方案 #### 使用异步任务或多线程技术 为了防止主线程被阻塞,开发人员应将任何可能耗费较长时间的任务移至后台线程。可以采用以下几种方式: - **Handler 和 Thread**: 创建一个新的工作线程来执行耗时任务,完成后通过 `Handler` 将结果传递回主线程。 ```java new Thread(new Runnable() { @Override public void run() { // 执行耗时任务 final String result = performLongRunningTask(); // 切换到主线程更新UI handler.post(new Runnable() { @Override public void run() { updateUiWithResult(result); } }); } private String performLongRunningTask() { try { Thread.sleep(5000); // 模拟耗时操作 } catch (InterruptedException e) { e.printStackTrace(); } return "Operation Completed"; } private void updateUiWithResult(String result) { textView.setText(result); } }).start(); ``` - **AsyncTask**(已废弃): 这是一个简化版的多线程工具类,在现代开发中已被官方建议弃用,推荐改用其他替代品如 `ExecutorService` 或者 Kotlin 协程。 - **Kotlin Coroutines**: 如果项目支持 Kotlin,则可利用协程实现更简洁优雅的并发控制逻辑。 ```kotlin GlobalScope.launch(Dispatchers.IO) { val result = longRunningOperation() withContext(Dispatchers.Main){ textView.text = result } } ``` #### 配置 ART 提升性能表现 自 Android 4.4 开始引入的新运行环境 ART 已经成为默认设置,并取代了旧版本中的 Dalvik VM[^2]。相比后者而言,ART 增加了一些改进措施以减少垃圾回收期间暂停的时间长度以及优化内存管理策略从而间接降低发生 ANRs 的可能性。 尽管如此,开发者仍然需要注意合理分配资源避免不必要的对象创建动作频繁触发起 GC 行动;另外也要关注特定 API 版本下是否存在潜在 bug 导致异常情况加剧等问题存在。 --- ### 总结 综上所述,要有效预防和解决 Android 中的应用不响应错误,关键是确保所有非即时反馈型的工作都应在独立子进程中完成而不是干扰 UI 更新流程所在的主进程运作状态之上加以考虑设计架构模式转换思路调整业务逻辑安排顺序等等因素综合考量之后再做决定采取相应行动步骤实施改善计划达成目标效果最佳化呈现给最终使用者良好体验感受度提升满意度水平达到预期标准范围内即可视为成功案例范例之一供参考学习借鉴模仿复制推广开来形成规模效应扩大影响力范围覆盖更多人群群体受益匪浅收获满满成果丰硕累累硕果满枝头喜迎丰收季节到来之际共襄盛举同庆佳节良辰美景好时光共享天伦之乐家庭幸福美满安康吉祥如意万事顺遂心想事成梦想成真一路高歌猛进勇攀高峰不断超越自我创造辉煌成就传奇人生价值最大化体现出来让生命绽放光彩闪耀光芒照亮黑暗前行道路指引方向引领潮流趋势发展走向光明未来前景无限美好灿烂辉煌! ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值