Android 的性能 V-保持APP的响应
来源:互联网 发布:淘宝腰脱九块九包官网 编辑:程序博客网 时间:2024/06/05 01:55
概述:
有时候可以写出通过世界上所有性能测试的代码, 但是依然感觉迟缓, 卡顿或者凝固, 或者花费很久才能处理输入. APP可以出现的最坏的情况就是一个” 应用程序无响应(Application Not Responding)”(ANR)对话框了. 在Android中, 如果APP有一段时间没有响应, 系统会显示一个这样的对话框:
这代表APP长时间不能响应, 所以系统会给用户提供一种可以退出APP的方法. 让APP可以一直响应用户的操作十分关键, 这样系统就不会显示这个对话框了. 下面将介绍为啥会出现这样的问题, 并如何避免该问题.
是什么引发了ANR?
通常会在用户的输入操作不响应的时候显示. 栗如, 如果一个APP在UI线程中执行某些I/O操作中卡住了(频繁的网络访问), 导致系统不能处理用户的输入事件. 或者APP花费太多时间来在UI线程中计算下一个游戏步骤等. 保证这些计算的效率十分的重要, 但是即便是最高效的代码还是要花时间.
在任何情况下, 当你的APP执行一个可能长时间的操作时, 你都应该避免在UI线程中执行它, 而是应该创建一个工作线程并在其中执行大部分的工作. 这可以让UI线程保持运行并避免系统认为你的UI卡住了. 因为通常线程时类级别的, 所以你可以认为响应是一个类问题(与基础代码性能对比, 它们是方法级别的问题). 在Android中, APP响应是由Activity管理器和窗口管理器系统服务负责监测的. Android将会在某个APP发生下列这些问题的时候显示一个ANR对话框:
l 5秒钟之内不响应一个输入事件.
l 一个BroadcastReceiver在10秒内还没有完成执行.
如何避免ANR:
Android APP通常都运行在默认的UI线程中. 这意味着APP在UI线程中做的任何消耗较多时间的事情都会导致触发ANR问题, 因为你的APP不给输入事件或者intent广播留时间. 因此, 任何在UI线程中的方法都应该尽量做轻量级的任务. 尤其是应该在关键的生命周期方法中做尽量少的事情, 比如onCreate()和onResume()方法. 可能会执行长时间的操作, 比如网络或者数据库操作, 或者运算量很大的计算操作比如缩放Bitmap, 这些都应该在工作线程中执行(或者在通过异步请求数据库操作).
创建一个工作线程用于长时间操作的最高效的方式是使用AsyncTasklei. 只需要简单的继承AsyncTask并实现其中的doInBackground()方法来执行工作即可. 如果需要发送进度给用户, 可以调用publishProgress(), 这会调用onProgressUpdate()回调方法. 从该方法中, 就可以修改UI来提醒用户了(它是在UI线程中运行的. 栗如:
privateclass DownloadFilesTaskextends AsyncTask<URL,Integer, Long> {
// Do thelong-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 iscalled each time you call publishProgress()
protected void onProgressUpdate(Integer... progress){
setProgressPercent(progress[0]);
}
// This iscalled when doInBackground() is finished
protected void onPostExecute(Long result){
showNotification("Downloaded "+ result + " bytes");
}
}
要执行这个工作线程, 只需要创建一个实例并执行execute()方法.
new DownloadFilesTask().execute(url1, url2, url3);
尽管更加复杂, 但是有时候你可能也会想要自定义自己的Thread或者HandlerThread类. 如果有这样的需求, 那么你应该通过Process.setThreadPriority()方法并传入THREAD_PRIORITY_BACKGROUND作为参数来设置thread优先级为”background”.如果你不通过这种方式来设置线程为一个较低的优先级, 那么该线程可能还是会减慢你的APP的速度, 因为它默认情况下跟UI线程是同一个优先级的.
如果你实现了自己的Thread或者HandlerThread, 要确保你的UI线程没有因为等待工作线程完成而阻塞– 不要调用Thread.wait()或者Thread.sleep(). 而是应该在UI线程中提供一个Handler来接收其它线程的完成消息. 通过这种方法设计你的APP将会让你的APP UI线程保持对输入的响应并因此而避免由5秒没响应而产生的ANR对话框.
BroadcastReceiver有一个特殊的约束, 就是它所执行的内容应该是小而离散型的, 比如保存设置或者注册一个Notification. 就好像其它在UI线程中调用的方法那样, APP应该避免在Broadcast receiver中执行可能长时间的操作或者计算, 如果需要长时间的响应一个broadcast你的APP应该使用一个IntentService.
提示: 你可以使用StrictMode来帮助查找那些长时间执行的操作比如网络或者数据库操作.
强化响应能力:
通常, 在一个APP中, 100到200ms是一个让用户感知到响应缓慢的阈值. 这里有一些额外的建议可以让你的APP运行起来更加流畅(不在避免ANR的范围内):
l 如果你的APP正在后台执行工作来响应用户的操作, 那么应该为用户显示一个进度条.
l 尤其是对游戏而言, 应该在工作线程中完成对移动的计算.
l 如果你的APP拥有一个事件比较耗时的初始化启动阶段, 考虑显示一个启动界面或者尽可能快的渲染显示主界面, 表示加载正在进行中, 并异步的填充信息. 不管那种情况, 你应该显示一些东西来表明正在做事情, 免得用户以为APP卡住了.
l 使用性能工具比如Systrace和Traceview来判断APP响应中的瓶颈.
参考: https://developer.android.com/training/articles/perf-anr.html
- Android 的性能 V-保持APP的响应
- 保持你的应用程序响应
- android app的类响应式设计
- 基于UI响应时间的移动App性能测试解决方案
- 保持你的应用可响应
- 提高Android App性能的技巧(转载)
- Android的app性能测试--流量
- Android APP 性能优化的一些思考
- App保持登录状态的常用方法
- 保持Oracle数据库的优良性能
- 如何保持Oracle数据库的优良性能
- 如何保持Oracle数据库的优良性能
- 如何保持Oracle数据库的优良性能
- 如何保持Oracle数据库的优良性能
- 如何保持Oracle数据库的优良性能
- <等待翻译>Android Wear 进阶 2.3 Keeping Your App Visible 保持你的应用可见
- Android终端APP访问服务器保持在同一个session的方式
- WEB APP的性能
- LeetCode 2015.7.21-2015.7.24 144,141,136,137,129,22,238,122,121,24
- NSValue和NSNumber(OC的包装类)
- LeetCode 2015.7.25 125,28,169,155,7,160,1
- LeetCode 2015.7.26 116,108,96,94,35,80,77,74,73
- xss的那些有卵用和没有卵用(一)
- Android 的性能 V-保持APP的响应
- LeetCode 2015.7.27 64,62,59,466,48,53,113,16
- (0)Leap Motion简介
- LeetCode 2015.7.28-2015.8.3 50,49,55,120,199,63,40
- poj 1033 文件移动
- LeetCode 2015.8.6 17,216,131,215,230,34,92
- LeetCode 2015.8.7 173,75,39,78,82,90,103
- 常用的消息摘要算法小总结
- USACO Transformations 解题日志