我是靠谱客的博主 傻傻大白,这篇文章主要介绍笔试题:ANR的类型与避免方法,现在分享给大家,希望可以做个参考。

对于你的应用中任何可能长时间执行的操作,你都不应该执行在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来判断程序中影响响应性的瓶颈。

转自:https://www.cnblogs.com/CVstyle/p/6384049.html

最后

以上就是傻傻大白最近收集整理的关于笔试题:ANR的类型与避免方法的全部内容,更多相关笔试题:ANR内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(59)

评论列表共有 0 条评论

立即
投稿
返回
顶部