可能会存在这样的状况,你写的代码经过了世界上全部的性能测试,但当用户尝试使用你的应用程序时,仍然让用户感到不爽。应用程序响应不够灵敏的地方包括——反映迟钝,挂起或冻结很长时间,或者须要花费很长的时间来处理输入。android
在Android上,若是你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称做应用程序无响应(ANR:Application Not Responding)对话框。用户能够选择让程序继续运行,可是,他们在使用你的应用程序时,并不但愿每次都要处理这个对话框。所以,在程序里对响应性能的设计很重要,这样,系统不会显示ANR给用户。数据库
通常说来,若是应用程序不能响应用户输入的话,系统会显示一个ANR。例如,一个应用程序阻塞在一些I/O操做上(一般是网络访问),这时,应用程序的主线程就不能再处理用户的输入事件。通过必定的时间后,系统认为应用程序已经挂起,并显示ANR来让用户选择杀死应用程序。网络
类似地,若是你的应用程序花费太多的时间来构建详细的内存结构,或者也许是在游戏里花费太多时间来计算下一步移动,这时,系统会认为你的应用程序已经挂起。所以,确保这些计算是高效的每每很重要,但即便是最高效的代码仍然须要花费时间来运行。异步
在这两种状况下,解决的方法一般是建立一个子线程,而后在线程里作你的大部分工做。这能让主线程(驱动UI事件循环)保持运行,并阻止系统认为你的代码已经冻结。由于这些线程一般是在类级别上完成的,所以,你能够认为响应性能问题是一个类的问题。(与基本性能相比而言,基本性能问题认为是方法级别的问题)性能
这篇文章将讨论Android系统如何判断一个应用程序处于无响应状态,并为保证应用程序的响应性提供向导。测试
这篇文章囊括这些主题:spa
· 什么引起了ANR?线程
· 如何避免ANR?设计
· 加强响应灵敏性blog
1)什么引起了ANR?
在Android里,应用程序的响应性是由Activity Manager和Window Manager系统服务监视的。当它监测到如下状况中的一个时,Android就会针对特定的应用程序显示ANR:
· 在5秒内没有响应输入的事件(例如,按键按下,屏幕触摸)
· BroadcastReceiver在10秒内没有执行完毕
一个ANR对话框显示给用户
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或者快速显示主画面并异步来填充这些信息。在这两种状况下,你都应该显示正在进行的进度,以避免用户认为应用程序被冻结了。