可能你写的代码在性能测试上表现良好,但是你的应用仍然有时候会反应迟缓(sluggish),停顿(hang)或者长时间卡死(frezze),或者应用处理输入的数据花费时间过长。对于你的应用来说最槽糕的事情是出现”程序无响应(Application Not Responding)” (ANR)的警示框。

在Android中,系统通过显示ANR警示框来保护程序的长时间无响应。对话框如下:

此时,你的应用已经经历过一段时间的无法响应了,因此系统提供用户可以退出应用的选择。为你的程序提供良好的响应性是至关重要的,这样才能够避免系统为用户显示ANR的警示框。

这节课描述了Android系统是如何判断一个应用不可响应的。这节课还会提供程序编写的指导原则,确保你的程序保持响应性。

是什么导致了ANR?(What Triggers ANR?)

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

对于你的应用中任何可能执行时间长的操作,你都不应该执行在UI线程。你可以创建一个工作线程,把那些操作都执行在工作线程中。这确保了UI线程(这个线程会负责处理UI事件) 能够顺利执行,也预防了系统因代码僵死而崩溃。因为UI线程是和类级别相关联的,你可以把相应性作为一个类级别(class-level)的问题(相比来说,代码性能则属于方法级别(method-level)的问题)

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

  • 对输入事件(例如硬件点击或者屏幕触摸事件),5秒内都无响应。
  • BroadReceiver不能够在10秒内结束接收到任务。

如何避免ANRs(How to Avoid ANRs)

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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():

1
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的长时间任务。

Tip: 你可以使用StrictMode来帮助寻找因为不小心加入到UI线程的潜在的长时间执行的操作,例如网络或者DB相关的任务。

增加响应性(Reinforce Responsiveness)

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

  • 如果你的程序需要响应正在后台加载的任务,在你的UI中可以显示ProgressBar来显示进度。
  • 对游戏程序,在工作线程执行计算的任务。
  • 如果你的程序在启动阶段有一个耗时的初始化操作,可以考虑显示一个闪屏,要么尽快的显示主界面,然后马上显示一个加载的对话框,异步加载数据。无论哪种情况,你都应该显示一个进度信息,以免用户感觉程序有卡顿的情况。
  • 使用性能测试工具,例如Systrace与Traceview来判断程序中影响响应性的瓶颈。
转载:http://hukai.me/android-training-performance-anr/

Android Training - 避免程序无响应ANR相关推荐

  1. 鸿蒙系统测试失败,ANR-WatchDog-ohos: 一个简单的监测程序,可检测到鸿蒙系统的 ANR(Application Not Response-应用程序无响应)错误并引发有意义的异常...

    ANR-WatchDog-ohos 一个简单的监测程序,可检测到鸿蒙系统的 ANR(Application Not Response-应用程序无响应)错误并引发有意义的异常 项目名称:ANR-Watc ...

  2. 测试人员遇到Android APP崩溃和无响应手足无措?

    这2天,在测APP兼容性时,遇到APP奔溃闪退的情况.将问题反馈给开发后,开发自己调试后,没有复现.由于又是远程,base地不在一块,我总不能把手机寄过去吧,那也太费事了. 所以就想到,提供明确的报错 ...

  3. chm打开秒退_Mac_Mac电脑程序无响应怎么办?Mac程序无响应解决方法,虽然Mac电脑一向以运行稳定、 - phpStudy...

    Mac电脑程序无响应怎么办?Mac程序无响应解决方法 虽然Mac电脑一向以运行稳定.流畅而著称,但Mac电脑运行时间长了,难免也会遇到程序卡死无响应.一直"转菊花"的情况,可能是由 ...

  4. 您没有权限来打开应用程序_苹果建议:除非应用程序无响应,否则不要滑动强制退出...

    紫金财经2月26日消息 今日,苹果公司发布的一条建议,成为了微博热搜的话题.苹果建议除非应用程序无响应,否则不要滑动强制退出. 苹果公司表示,滑动关闭iPhone的应用程序可能会缩短电池寿命,并使设备 ...

  5. C# OpenFileDialog.ShowDialog 打不开,程序无响应(错误的解决)

    1:C# OpenFileDialog.ShowDialog 打不开,程序无响应 环境:win7 .Net framework2.0 现象; c#写的一个程序,在xp下点击文件打开按钮没有任何问题,但 ...

  6. 简单有效的解决打开Xcode一直loading并显示程序无响应问题

    简单有效的解决打开Xcode一直loading并显示程序无响应问题 项目场景: 问题描述: 原因分析: 解决方案: 项目场景: 打开一个旧的项目文件的 main.storyboard 时候Xcode崩 ...

  7. mac securecrt程序无响应_如何重置mac上的系统管理控制器smc教程

    虽然mac是一款十分高端的个人笔记本电脑,但是mac也会有出现故障的时候,比如风扇高速转动.键盘背光灯行为有些异常异常等等,那极有可能是你的系统管理控制器smc出现了问题,所以今天小编就来科普大家如何 ...

  8. mac版crt8.0.2打开无响应怎么办_Mac电脑程序无响应怎么办?教你强制退出无响应程序...

    Mac电脑运行时间长了,难免也会遇到程序卡死无响应的情况,可能是由于程序冲突.缓存不足或者一些bug等情况导致,这个时候我们就需要强制退出这个程序了,一起来看看如何强制退出无响应程序吧! 快捷键强制退 ...

  9. mac securecrt程序无响应_在Mac上查看和终止进程的方法

    当Mac速度变慢或开始异常运行时,可能是因为正在后台运行的应用程序运行异常.而且,如果不是引起问题的应用程序,几乎可以肯定是与macOS或辅助服务相关的进程. 解决此问题通常很简单,就像杀死进程一样, ...

最新文章

  1. C# ACCESS数据库操作类
  2. 各种语言下 static 详解
  3. 管道符、shell变量、环境变量配置文件
  4. android设置系统横屏方案
  5. “白加黑”远控木马技术分析及手杀方案
  6. 小b删列(51Nod-2523)
  7. TS Type As
  8. 负载敏感系统详解_宣布Enarx用于运行敏感工作负载
  9. NYOJ-布线问题(最短路)
  10. PHP如何获取用户IP地址
  11. ActivityMQ 事务
  12. 从NASA获取全球气象数据
  13. 遗传算法求解TSP问题(C++实现)
  14. mi5splus android9,小米5SPlus 安卓9.0 原生体验 LineageOS16.0 ROOT
  15. 使用cmd命令查看占用进程并结束进程
  16. 7步打造持续盈利的会员体系
  17. html计算梯形的面积,梯形的面积计算
  18. Xshell下载文件到本地
  19. 51单片机开发实例 基于51单片机的万年历
  20. 2020最受欢迎主动降噪蓝牙耳机盘点,五款性能超强蓝牙耳机推荐

热门文章

  1. 清华镜像源下载Android源码
  2. 五笔字根--good
  3. cad 中的块与块参照
  4. SEO排名,seo排名工具
  5. 饿了吗 系统_阿里反击开始!飞猪“100亿”补贴来袭,美团挺得住吗?
  6. 在虚拟机中安装并激活Windows 10
  7. 音视频技术开发周刊 | 202
  8. 都市圈-智慧应急综合业务管理平台重磅发布
  9. mysql查询关键字报错_mysql中in关键字查询时的问题? 400 报错-问答-阿里云开发者社区-阿里云...
  10. 开发经验总结(打造更优秀的日志输出工具类)