In Android, the system guards against applications that are insufficiently responsive for a period of time by displaying a dialog that says your app has stopped responding, such as the dialog in Figure 1.

At this point, your app has been unresponsive for a considerable period of time so the system offers the user an option to quit the app. 为你的程序提供良好的响应性是至关重要的,这样才能够避免系统为用户显示ANR的警示框。

疑问:

Android系统是如何判断应用程序无响应的?

为什么会导致ANR?是什么导致了ANR?

通常来说,系统会在程序无法响应用户的输入事件时显示ANR。例如,如果一个程序在UI线程执行I/O操作(通常是网络请求或者是文件读写),这样系统就无法处理用户的输入事件。或者是应用程序在UI线程花费了太多的时间用来建立一个复杂的数据结构,又或者是在一个游戏程序的UI线程中执行了一个复杂耗时的计算移动的操作。确保那些计算操作高效是很重要的,不过即使是最高效的代码也是需要花时间执行的。

对于你的应用中任何可能长时间执行的操作,你都不应该执行在UI线程。你可以创建一个工作线程(a worker thread),把那些操作都执行在工作线程中。This keeps the UI thread (which drives the user interface event loop) running and prevents the system from concluding that your code has frozen. 这确保了UI线程(这个线程会负责处理UI的事件循环) 能够顺利执行,也预防了系统因代码僵死而崩溃。因为UI线程是和类级别相关联的,你可以把响应性作为一个类级别(class-level)的问题(相比来说,代码性能则属于方法级别(method-level)的问题)

在Android中,程序的响应性是由Activity Manager与Window Manager系统服务来负责监控的。当系统监测到下面的条件之一时会显示ANR的对话框:

No response to an input event (such as key press or screen touch events) within 5 seconds. 对输入事件(例如硬件点击或者屏幕触摸事件),5秒内都无响应。

A BroadcastReceiver hasn't finished executing within 10 seconds. BroadReceiver不能够在10秒内结束接收到任务。

如何避免ANR?

Android程序通常是执行在默认的UI线程(也就是main线程)中的,这意味着在UI线程中执行的任何长时间的操作都可能触发ANR,因为程序没有给自己处理输入事件或者broadcast事件的机会。

因此,任何执行在UI线程的方法都应该尽可能的简短快速。特别是,在Activity的生命周期的关键方法onCreate()与onResume()方法中应该尽可能的做比较少的事情。类似网络或者DB操作等可能长时间执行的操作,或者是类似调整bitmap大小等需要长时间计算的操作,都应该执行在工作线程中。(在DB操作中,可以通过异步的网络请求)。

为了执行一个长时间的耗时操作而创建一个工作线程最方便高效的方式是使用AsyncTask。只需要继承AsyncTask并实现doInBackground()方法来执行任务即可。为了把任务执行的进度呈现给用户,你可以执行publishProgress()方法,这个方法会触发onProgressUpdate()的回调方法。在onProgressUpdate()的回调方法中(它执行在UI线程),你可以执行通知用户进度的操作,例如:

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
// Do the long-running work in here
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
// This is called each time you call publishProgress()
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
// This is called when doInBackground() is finished
protected void onPostExecute(Long result) {
showNotification("Downloaded " + result + " bytes");
}
}

运行这个工作线程很简单,只需要创建实例并调用execute()即可:

new DownloadFilesTask().execute(url1, url2, url3);

相比起AsycnTask来说,创建自己的线程或者HandlerThread稍微复杂一点。如果你想这样做,你应该通过Process.setThreadPriority()并传递THREAD_PRIORITY_BACKGROUND来设置线程的优先级为"background"。如果你不通过这个方式来给线程设置一个低的优先级,那么这个线程仍然会使得你的应用显得卡顿,因为这个线程默认与UI线程有着同样的优先级。

如果你实现了Thread或者HandlerThread,请确保你的UI线程不会因为等待工作线程的某个任务而去执行Thread.wait()或者Thread.sleep()。UI线程不应该去等待工作线程完成某个任务,你的UI线程应该提供一个Handler给其他工作线程,这样工作线程能够通过这个Handler在任务结束的时候通知UI线程。使用这样的方式来设计你的应用程序可以使得你的程序UI线程保持响应性,以此来避免ANR。

BroadcastReceiver有特定执行时间的限制说明了broadcast receivers应该做的是:简短快速的任务,避免执行费时的操作,例如保存数据或者注册一个Notification。正如在UI线程中执行的方法一样,程序应该避免在broadcast receiver中执行费时的长任务。但不是采用通过工作线程来执行复杂的任务的方式,你的程序应该启动一个IntentService来响应intent broadcast的长时间任务。

如何增强响应性?

通常来说,100ms - 200ms是用户能够察觉到卡顿的上限。这样的话,下面有一些避免ANR的技巧:

1. 如果你的程序需要响应正在后台加载的任务,在你的UI中可以显示ProgressBar来显示进度。

2. 对游戏程序,在工作线程执行计算的任务。

3. 如果你的程序在启动阶段有一个耗时的初始化操作,可以考虑显示一个闪屏,要么尽快的显示主界面,然后马上显示一个加载的对话框,异步加载数据。无论哪种情况,你都应该显示一个进度信息,以免用户感觉程序有卡顿的情况。

4. 使用性能测试工具,例如Systrace与Traceview来判断程序中影响响应性的瓶颈。

如何避免Android程序的ANR?的更多相关文章

  1. Android中的ANR

    有过Android开发经历的人都不会对ANR陌生,它和崩溃一样是程序设计的问题.本文将以较为深入的视角来介绍什么是ANR,出现场景,如何避免以及如何定位分析ANR,希望可以帮助大家在编写程序时有所帮助 ...

  2. Android 系统稳定性 - ANR(二)(转)

    编写者:李文栋P.S. OpenOffice粘贴过来后格式有些混乱. 1.2 如何分析ANR问题 引起ANR问题的根本原因,总的来说可以归纳为两类: 应用进程自身引起的,例如: 主线程阻塞.挂起.死循 ...

  3. Android 程序员必须掌握的三种自动化测试方法

    在日常的开发中,尤其是app开发,因为不像web端那样 出错以后可以热更新,所以app开发 一般对软件质量有更高的要求(你可以想一下 一个发出去的版本如果有重大缺陷 需要强制更新新客户端是多么蛋疼的事 ...

  4. 【原创】Android 系统稳定性 - ANR(二)

    文章都为原创,转载请注明出处,未经允许而盗用者追究法律责任. 很久之前写的了,留着有点浪费,共享之.编写者:李文栋P.S. OpenOffice粘贴过来后格式有些混乱. 1.2 如何分析ANR问题 引 ...

  5. Android 程序员必须知道的 53 个知识点

    1. android 单实例运行方法 我们都知道 Android 平台没有任务管理器,而内部 App 维护者一个 Activity history stack 来实现窗口显示和销毁,对于常规从快捷方式 ...

  6. [转发]Android 系统稳定性 - ANR(二)

    文章都为原创,转载请注明出处,未经允许而盗用者追究法律责任. 很久之前写的了,留着有点浪费,共享之.编写者:李文栋P.S. OpenOffice粘贴过来后格式有些混乱. http://rayleeya ...

  7. 面试利器!字节跳动2021年Android程序员面试指导小册已开源

    整份手册分为两个部分,分别是:Java部分.Android部分.数据结构与算法篇.字节跳动2020年全年面试题总结篇! 每个知识点都有左侧导航书签页,看的时候十分方便,由于内容较多,这里就截取一部分图 ...

  8. 【定有惊喜】android程序员如何做自己的API接口?php与android的良好交互(附环境搭建),让前端数据动起来~

    一.写在前面 web开发有前端和后端之分,其实android还是有前端和后端之分.android开发就相当于手机app的前端,一般都是php+android或者jsp+android开发.androi ...

  9. 正在运行的android程序,按home键之后退回到桌面,在次点击程序图标避免再次重新启动程序解决办法

    正在运行的android程序,按home键之后退回到桌面,在次点击程序图标避免再次重新启动程序解决办法 例如:一个android程序包含两个Activity,分别为MainActivity和Other ...

随机推荐

  1. Yslow web性能测试插件

    YSlow可以对网站的页面进行分析,并告诉你为了提高网站性能,如何基于某些规则而进行优化. YSlow可以分析任何网站,并为每一个规则产生一个整体报告,如果页面可以进行优化,则YSlow会列出具体的修 ...

  2. delete web server(nginx)

    #!/bin/bash conf_dir1="/usr/local/nginx/conf/vhost.d" #conf_dir2="/usr/local/apache2/ ...

  3. Nginx配置笔记

    配置资源的缓存周期 location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {       root  www;       expires  3560d; } loca ...

  4. Python入门:求1-2+3-4+5...99的所有数的和

    num =1 sum =0 while num <=99: if num % 2 ==1: sum = sum + num num =num +1 print(sum) 2.求1-2+3-4+5 ...

  5. WebApi服务以及跨域设置

    WCF 它利用TCP.HTTP.MSMQ等传输协议构建“契约先行”的服务.WCF最初为基于SOAP的服务而设计[xml],繁琐.冗余.慢.沉重 WebApi 基于http协议,轻量级的,支持URL路由 ...

  6. java 使用jdbc连接Greenplum数据库和Postgresql数据库

    1.公司使用的Greenplum和Postgresql,确实让我学到不少东西.简单将使用jdbc连接Greenplum和Postgresql数据库.由于使用maven仓库,不能下载Greenplum的 ...

  7. ssh-keygen -t rsa 生成密钥对后如何校验

    ssh-keygen -t rsa 生成密钥对后如何校验一下呢ssh-keygen -y -f id_rsa > id_rsa.pub.tobecompared 然后对比一下id_rsa.pub ...

  8. Vs2017获取Git空仓库后创建解决方案及项目无法推送,推送失败的问题.

      与Git无关,因为远程是空文件夹,导致没有远程版本做对应提示更改或怎样,必须在创建人创建仓库的时候上传文件代码. https://developercommunity.visualstudio.c ...

  9. 【转】Crosswalk入门

    原文:https://www.mobibrw.com/2015/1934 Crosswalk是一款开源的web引擎.目前Crosswalk正式支持的移动操作系统包括Android和Tizen,在And ...

  10. javascript 和 下拉列表

    <form id="f"> <select size="1" name="s"> <option value= ...