Android官方开发文档Training系列课程中文版:如何避免ANR?

简介: 原文地址:http://android.xsoftlab.net/training/articles/perf-anr.html#anr尽管你写代码可能通过了世界上所有的性能测试,但是它还是可能会让人感觉到卡顿。

原文地址:http://android.xsoftlab.net/training/articles/perf-anr.html#anr

尽管你写代码可能通过了世界上所有的性能测试,但是它还是可能会让人感觉到卡顿。当应用卡的不成样子时,系统会给你弹一个”Application Not Responding”的对话框。

在Android中,系统会对那些长时间没有响应的应用采取一些措施:弹出一个对话框告诉用户APP已经停止了响应,如下图所示:

正出于这个原因,系统会在APP长时间没有响应的时候为用户提供一个退出APP的选项。所以使APP能够及时响应这一点是至关重要的,这样系统才不会向用户显示ANR对话框。

这节课我们会学习Android系统如何检测应用程序是否是未响应,以及应用程序如何保持响应能力的一些改进措施。

什么触发了ANR?

通常情况下,系统会在应用程序不再能够响应用户的输入时显示ANR对话框。比如,如果应用阻塞在了UI线程的IO操作上,那么系统就不能够处理用户的输入事件。或者应用花费了大量的时间在内存模型的构建上或者是在UI线程中计算了游戏的下一步动作。要记住:
即便是最高效的代码也需要花费时间来运行。

任何情况下都不要在UI线程中执行耗时操作,而是要将这些工作放在一个单独的线程中执行。这可以使UI线程保持流畅工作(UI线程负责驱动用户界面的事件循环)。

在Android中,应用程序的响应态由Activity Manager及Window Manager负责监控。系统会在侦测到以下状况时显示ANR对话框:

  • 对输入事件在5秒内没有作出响应。
  • BroadcastReceiver在10秒内没有执行完毕。

如何避免ANR?

Android应用程序默认运行在UI线程中。这意味着在UI线程中的任何耗时操作都会引发ANR问题,因为这会使应用程序给不到输入事件或者意图广播处理的机会。

因此,在UI线程中的每个方法都应当做尽可能少的工作,尤其是Activity的生命周期回调函数。像网络或数据库操作,或者大量的计算之类的耗时操作应当在工作线程中执行。

创建用于执行耗时操作的线程最便捷的方式莫过于使用AsyncTask了。只需要继承AsyncTask,然后重写doInBackground()就可以执行了。如果要向用户展示工作进度,你可以使用publishProgress()方法,它会回调onProgressUpdate()方法(该方法运行于UI线程)。
在onProgressUpdate()内我们可以更新进度条。

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

如果不采用这种方式,我们还有另一种实现方法:创建自己的Thread或HandlerThread。如果采用这种方法,那么应该设置该线程的优先级为”background”:通过Process.setThreadPriority()方法及参数THREAD_PRIORITY_BACKGROUND设置。
如果没有设置该优先级,那么该线程会使应用感到变慢,因为该线程的优先级默认与UI线程的优先级一致,它们会互相抢占CPU资源。

如果实现了自己的Thread或HandlerThread,那么要确保在等待其它工作线程完成之前UI线程不被阻塞—不要调用Thread.wait()或Thread.sleep()。如果需要等待其它线程的执行结果,可以为UI线程创建一个Handler。这样做可以使UI线程还可以对
输入事件保持响应能力。这样就可以避免5秒内无响应的ANR对话框出现。

BroadcastReceiver在执行时间上有特殊的限制,这意味着在其内部的工作一定是轻量级的:比如在后台做一些保存设置或者发送通知的工作。所以与UI线程中执行的方法一样,广播接收器内也应当杜绝耗时操作的出现。

TIP: 你可以使用StrictMode来发现UI线程中意外出现的耗时操作。

ANR相关优化

一般来说,100~200毫秒是用户所能感知到应用卡顿的极限。下面列出了一些可以避免应用程序ANR的一些点,同样也有助于防止出现卡顿的情况:

  • 如果应用需要对用户输入做大量的后台工作,可以显示一个进度表示工作正在进行。
  • 对于游戏类的复杂计算,应该将这些工作放在工作线程中执行。
  • 如果应用在初始化阶段需要花费一些时间,可以考虑显示一个闪屏页面或者尽可能快的显示主界面:展示加载正在进行,并进行异步数据填充。在这些情况下都应当表明任务正在进行,以免让用户认为应用已经卡死。
  • 使用SystraceTraceview等性能工具检查APP的响应瓶颈。
目录
相关文章
|
5月前
|
移动开发 前端开发 Android开发
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
907 12
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
5月前
|
移动开发 JavaScript 应用服务中间件
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
756 5
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
5月前
|
移动开发 Rust JavaScript
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
958 4
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
6月前
|
开发工具 Android开发
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
734 11
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
|
5月前
|
移动开发 Android开发
【03】建立隐私关于等相关页面和内容-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【03】建立隐私关于等相关页面和内容-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
285 0
|
6月前
|
Java 开发工具 Maven
【01】完整的安卓二次商业实战-详细的初级步骤同步项目和gradle配置以及开发思路-优雅草伊凡
【01】完整的安卓二次商业实战-详细的初级步骤同步项目和gradle配置以及开发思路-优雅草伊凡
731 6
|
8月前
|
移动开发 Java 编译器
Kotlin与Jetpack Compose:Android开发生态的演进与架构思考
本文从资深Android工程师视角深入分析Kotlin与Jetpack Compose在Android系统中的技术定位。Kotlin通过空安全、协程等特性解决了Java在移动开发中的痛点,成为Android官方首选语言。Jetpack Compose则引入声明式UI范式,通过重组机制实现高效UI更新。两者结合不仅提升开发效率,更为跨平台战略和现代架构模式提供技术基础,代表了Android开发生态的根本性演进。
351 0
|
算法 Java API
Android性能优化面试题经典之ANR的分析和优化
Android ANR发生于应用无法在限定时间内响应用户输入或完成操作。主要条件包括:输入超时(5秒)、广播超时(前台10秒/后台60秒)、服务超时及ContentProvider超时。常见原因有网络、数据库、文件操作、计算任务、UI渲染、锁等待、ContentProvider和BroadcastReceiver的不当使用。分析ANR可借助logcat和traces.txt。主线程执行生命周期回调、Service、BroadcastReceiver等,避免主线程耗时操作
566 3
|
Java 数据库 Android开发
|
Android开发 数据库 数据格式

热门文章

最新文章