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


认真的紫菜
5 声望1 粉丝