Android性能优化面试题经典之ANR的分析和优化

简介: Android ANR发生于应用无法在限定时间内响应用户输入或完成操作。主要条件包括:输入超时(5秒)、广播超时(前台10秒/后台60秒)、服务超时及ContentProvider超时。常见原因有网络、数据库、文件操作、计算任务、UI渲染、锁等待、ContentProvider和BroadcastReceiver的不当使用。分析ANR可借助logcat和traces.txt。主线程执行生命周期回调、Service、BroadcastReceiver等,避免主线程耗时操作

本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点

造成ANR的条件

以下四个条件都可以造成ANR发生:

  • InputDispatching Timeout:5秒内无法响应屏幕触摸事件或键盘输入事件

  • BroadcastQueue Timeout :在执行前台广播(BroadcastReceiver)的onReceive()函数时10秒没有处理完成,后台为60秒。

  • Service Timeout :前台服务20秒内,后台服务在200秒内没有执行完毕。

  • ContentProvider Timeout :ContentProvider的publish在10s内没进行完。

常见的耗时操作

在Android开发中,导致应用程序无响应(ANR)的一些常见耗时操作包括:

网络操作

例如,HTTP 请求、下载文件、访问REST API等。网络操作通常需要较长的时间,尤其在网络条件不好的情况下。

数据库操作

大量的数据库查询、插入、更新、删除操作可能会占用大量时间。特别是如果在主线程进行这些操作时,会直接导致ANR。

文件读写

对大文件进行读写操作也可能非常耗时。这些操作同样不应在主线程中进行。

1、文件相关的一些API都要小心

包括但不限于 new File(),exists(),lastModified()等

2、读写一些assets目录下的文件,比如字体,频繁在布局里读取也会很耗时

复杂的计算任务

某些计算密集型任务如图像处理、加解密操作、复杂算法计算等,若在主线程中执行,也会导致界面卡死。

UI 渲染

复杂的UI更新或在UI线程中进行过多的绘图操作,也可能导致ANR。例如,加载巨大的图片或者执行频繁的动画。

锁等待

如果线程在主线程上获取锁资源(如synchronized块)时等待时间太长,也会引发ANR。

ContentProvider 访问

使用ContentProvider访问大量数据或复杂查询,如果在主线程中进行,也会导致ANR。

BroadcastReceivers

长时间运行的BroadcastReceiver(例如,在onReceive()中执行耗时操作)也可能导致ANR。广播接收器应该尽快完成其工作或将耗时任务移到异步线程。

Service 启动

如果在主线程中启动较为耗时的Service,也可能导致ANR。所以服务启动过程中的耗时操作应该在子线程中执行。

系统Service的调用

如果在主线程中调用系统的一些服务,也是耗时的,虽然不一定会ANR,但是也要注意。

比如包管理服务PackageManager

分析ANR的方式:

  • 分析logcat清晰地记录了ANR发生的时间,以及线程的tid
  • 分析traces.txt文件,搜索anr关键字

哪些地方是执行在主线程的

  • Activity的所有生命周期回调都是执行在主线程的.
  • Service默认是执行在主线程的.
  • BroadcastReceiver的onReceive回调是执行在主线程的.
  • 没有使用子线程的looper的Handler的handleMessage, post(Runnable)是执行在主线程的.
  • AsyncTask的回调中除了doInBackground, 其他都是执行在主线程的.
  • View的post(Runnable)是执行在主线程的.

使用子线程的方式有哪些

Java

  • 启Thread方式,或是线程池
  • 使用AsyncTask
  • HandlerThread
  • IntentService,Service是运行在主线程的, 然而IntentService是运行在子线程的.(官方建议使用JetPack组件中的WorkManager或者JobIntentService类代替它)
  • 使用Thread和HandlerThread时, 为了使效果更好, 建议设置Thread的优先级偏低一点

欢迎关注我的公众号AntDream查看更多精彩文章!

目录
相关文章
|
2天前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了两者的开发环境差异,从编程语言、工具框架到用户群体和市场份额进行了全面比较。通过数据支撑和案例分析,揭示了不同平台的优势与局限,旨在为开发者提供决策参考,同时预测未来发展趋势。
|
3天前
|
Android开发 Kotlin
Android面试题之kotlin中怎么限制一个函数参数的取值范围和取值类型等
在Kotlin中,限制函数参数可通过类型系统、泛型、条件检查、数据类、密封类和注解实现。例如,使用枚举限制参数为特定值,泛型约束确保参数为Number子类,条件检查如`require`确保参数在特定范围内,数据类封装可添加验证,密封类限制为一组预定义值,注解结合第三方库如Bean Validation进行校验。
15 6
|
3天前
|
Android开发
Android面试题之自定义View注意事项
在Android开发中,自定义View主要分为四类:直接继承View重写onDraw,继承ViewGroup创建布局,扩展特定View如TextView,以及继承特定ViewGroup。实现时需注意:支持wrap_content通过onMeasure处理,支持padding需在onDraw或onMeasure/onLayout中处理。避免在View中使用Handler,使用post系列方法代替。记得在onDetachedFromWindow时停止线程和动画以防止内存泄漏。处理滑动嵌套时解决滑动冲突,并避免在onDraw中大量创建临时对象。
13 4
|
1天前
|
Android开发
Android面试题之View的invalidate方法和postInvalidate方法有什么区别
本文探讨了Android自定义View中`invalidate()`和`postInvalidate()`的区别。`invalidate()`在UI线程中刷新View,而`postInvalidate()`用于非UI线程,通过消息机制切换到UI线程执行`invalidate()`。源码分析显示,`postInvalidate()`最终调用`ViewRootImpl`的`dispatchInvalidateDelayed`,通过Handler发送消息到UI线程执行刷新。
11 1
|
4天前
|
Android开发 Kotlin
Android面试题之 Kotlin中退出迭代器的方式有哪些
在Android和Kotlin中,遍历集合时可使用迭代器结合`break`提前终止循环。例如,使用`while`和迭代器,或用`forEach`配合`return@forEach`来中断遍历。若需退出外层函数,可定义自定义标签。在遍历并删除元素时,这些技巧尤其有用。
11 3
|
4天前
|
API 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动操作系统的两大阵营中,安卓和iOS各占据着重要的地位。本文旨在深入探讨两种系统在开发环境方面的异同,通过对开发工具、语言、框架、API以及生态系统的综合比较,揭示各自在应用开发上的优势与挑战。文章将基于最新的市场数据和技术发展进行论述,以期为开发者提供有价值的参考信息,并预测未来可能的发展趋势。
10 1
|
4天前
|
监控 Java 开发者
Java面试题:如何使用JVM工具(如jconsole, jstack, jmap)来分析内存使用情况?
Java面试题:如何使用JVM工具(如jconsole, jstack, jmap)来分析内存使用情况?
11 2
|
4天前
|
设计模式 安全 NoSQL
Java面试题:结合单例模式与Java内存管理,设计一个线程安全的单例类?分析Java多线程工具类ExecutorService与Java并发工具包中的工具类,设计一个Java并发框架的分布式锁实现
Java面试题:结合单例模式与Java内存管理,设计一个线程安全的单例类?分析Java多线程工具类ExecutorService与Java并发工具包中的工具类,设计一个Java并发框架的分布式锁实现
12 0
|
4天前
|
设计模式 安全 Java
Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
14 0
|
Java 数据库 Android开发