ANR-[Android_YangKe]

什么是 ANR

ANR 是指应用程序无响应(Application Not Responding)

在Android中,该系统通过显示一个对话框来防止在一段时间内响应不足的应用程序,该对话框显示您的应用程序已停止响应,例如图1中的对话框。此时,您的应用程序在相当长的一段时间内不会有反应的时间,因此系统为用户提供退出应用程序的选项。

本文档描述了Android 系统如何确定应用程序是否没有响应,并提供了确保应用程序保持响应的准则

《ANR-[Android_YangKe]》 yangke.png

ANR 如何触发

通常,如果应用程序无法响应用户输入,系统将显示 ANR。 例如,如果应用程序阻塞 UI 线程上的某些 I / O操作(通常是网络访问),因此系统无法处理传入的用户输入事件。

在您的应用程序执行潜在的长度操作的任何情况下,您不应该在 UI 线程上执行工作,而是创建一个工作线程并执行大部分工作,这样可以保持 UI 线程(驱动冻结的线程) 这样的线程通常是在类级别上完成的,你可以将响应性视为一个类问题(与基本代码性能进行比较,这是一个方法级的关注点)

在 Android中,应用程序响应由 Activity Manager 和 Window Manager 系统服务进行监控。 当检测到以下情况之一时,Android 将显示特定应用程序的 ANR 对话框:

  • 在5秒内没有响应输入事件(如按键或屏幕触摸事件)
  • 广播接收器在10秒内尚未完成执行

注 ANR 对话框并不总是显示给用户,但出现 ANR 对话框的应用一定存在性能问题。

怎样避免 ANR

默认情况下,Android 应用程序通常在单线程上运行,“UI线程”或“主线程”)。这意味着您的应用程序在 UI 线程中执行的任务需要很长时间才能触发 ANR 对话框,因为您的应用程序并没有给自己一个处理输入事件或意图广播的机会。

因此,在 UI 线程中运行的任何方法都应该尽可能少的工作在该线程上。特别地,Activity 应尽可能少地在关键的生命周期方法中设置,如 onCreate()和 onResume()。潜在的长时间运行操作(如网络或数据库操作)或主线程进行大量计算(如调整位图大小)应在工作线程中完成(或者在数据库操作的情况下,通过异步请求)。

使用 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);

虽然它比 AsyncTask 更复杂,但您可能想要创建自己的 Thread 或HandlerThread 类。如果这样做,您应该通过调用 Process.setThreadPriority()并传递 THREAD_PRIORITY_BACKGROUND 来将线程优先级设置为“background”优先级。如果你没有以这种方式将线程设置为较低优先级,那么线程可能会减慢你的应用程序,因为默认情况下它与 UI 线程的优先级相同。

如果您实现 Thread 或 HandlerThread,请确保您的UI线程在等待工作线程完成时不会阻塞 – 请勿调用 Thread.wait()或 Thread.sleep()。等待工作线程完成时,您的主线程不应阻塞,而是为其他线程提供一个处理程序,以便在完成后发回。以这种方式设计您的应用程序将允许您的应用程序的UI线程保持对输入的响应,从而避免由5秒输入事件超时引起的 ANR 对话框。

BroadcastReceiver 执行时间的具体约束强调了广播接收者要做的事情:在后台工作量小,如保存设置或注册通知。所以与 UI 线程中调用的其他方法一样,应用程序应避免在广播接收器中潜在的长时间运行的操作或计算。但是,如果需要采取潜在的长时间运行操作来响应意向广播,而不是通过工作线程进行密集的任务,则应用程序应启动 IntentService。

BroadcastReceiver 对象的另一个常见问题是当它们执行得太频繁时发生。频繁的后台执行可以减少其他应用程序可用的内存量。有关如何有效启用和禁用 BroadcastReceiver 对象的更多信息,请参阅按需处理广播接收器。

提示:您可以使用 StrictMode
来帮助您找到可能长时间运行的操作,例如网络或数据库操作,您可能会意外地在主线程上执行此操作。

增强反应速度

通常,100到200ms是用户在应用程序中感觉到缓慢的阈值。 因此,这里还有一些额外的提示,除了您应该做什么以避免 ANR,使您的应用程序似乎响应用户:

  • 如果您的应用程序在后台执行响应用户输入的工作,则显示正在进行进度(例如,在用户界面中使用 ProgressBar)。
  • 对于游戏具体来说,做一个工作线程的移动计算。
  • 如果您的应用程序具有耗时的初始设置阶段,请考虑显示启动屏幕或尽快呈现主视图,指示正在进行加载并异步填充信息。 在这两种情况下,您应该以某种方式指出进展情况,以免用户察觉到应用程序被冻结。
  • 使用 SystraceTraceview 等性能工具来确定应用程序响应速度的瓶颈。

ANR 日志

当设备上的 /data/anr/traces.txt 文件中遇到 ANR 时,Android 会存储一些跟踪信息。 您可以通过以 root 用户身份在设备上启动 shell 会话从模拟器获取文件,如以下命令行示例所示:

adb root
adb shell
cat /data/anr/traces.txt 

最好的学习网站:https://developer.android.com/topic/performance/vitals/anr.html#fix_the_problem

ps: 喜欢有帮助的话: 双击、评论、转发,动一动你的小手让更多的人知道!关注 帅比-杨

    原文作者:Android_YangKe
    原文地址: https://www.jianshu.com/p/0be8c4823425
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞