本文首发于公众号“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查看更多精彩文章!