1.ANR错误定义
在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作“应用程序无响应”(ANR:Application Not Responding)对话框。用户可以选择“等待”而让程序继续运行,也可以选择“强制关闭”。因此,在程序里对响应性能的设计很重要,这样,系统不会显示ANR给用户。
默认情况下,在Android中Activity的最长执行时间是5秒(主要类型),BroadcastReceiver的最长执行时间的则是10秒,ServiceTimeout的最长执行时间是20秒(少数类型)。超出就会提示应用程序无响应(ANR错误)。
2.ANR错误出现原因
只有当应用程序的UI线程响应超时才会引起ANR 超时产生的原因包括:
①当前事件没有机会处理,例如UI线程正在响应另外的事件,当前事件被某个事件给阻塞掉了;
②当前事件正在处理 但是由于耗时太长没有能及时的完成。其他原因:
③在BroadcastReceiver里做耗时的操作或计算;
④CPU使用过高;
⑤发生了死锁;
⑥耗时操作的动画需要大量的计算工作,可能导致CPU负载过重。
二、ANR定位方式及优化
1.ANR错误定位
如果开发机器上出现ANR问题时,系统会生成一个traces.txt的文件放在/data/anr下,最新的ANR信息在最开始部分。通过adb命令将其导出到本地,输入以下字符:
2.供选的优化ANR问题的方式:
1)为了执行一个长时间的耗时操作而创建一个工作线程最方便高效的方式是使用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 doInBa
ckground() is finished
protected void onPostExecute(Long result) {
showNotification(“Downloaded " + result + " bytes”);
}
2)如果你实现了Thread或者HandlerThread,请确保你的UI线程不会因为等待工作线程的某个任务而去执行Thread.wait()或者Thread.sleep()。UI线程不应该去等待工作线程完成某个任务,你的UI线程应该提供一个Handler给其他工作线程,这样工作线程能够通过这个Handler在任务结束的时候通知UI线程。例如:
继承Thread类
new Thread(new Runnable() {
@Override
public void run() {
/**
耗时操作
*/
handler.post(new Runnable() {
@Override
public void run() {
/**
更新UI
*/
}
});
}
}).start();
实现Runnable接口
class PrimeRun implements Runnable {
long minPrime;
PrimeRun(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
PrimeRun p = new PrimeRun(143);
new Thread§.start();
使用HandlerThread
// 启动一个名为new_thread的子线程
HandlerThread thread = new HandlerThread(“new_thread”);
thread.start();
// 取new_thread赋值给ServiceHandler
private ServiceHandler mServiceHandler;
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
//默认Handler的handleMessage方法是运行在主线程中的,如果传入一个工作线程的Looper,则改变HandleMessage方法执行的所在线程
}
ndler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
//默认Handler的handleMessage方法是运行在主线程中的,如果传入一个工作线程的Looper,则改变HandleMessage方法执行的所在线程
}