ANR (Application Not Responding) 是 Android 中一个独有的概念。当你在操作 App 时候感觉界面卡顿,卡顿超过一定时间就会出现ARN 对话框。出现 ANR 主要是因为我们在主线程中做了太多耗时操作。这时你可以选择"等待"按钮,等待应用程序结束主线程的耗时操作,或者选择"确定"按钮,结束这个应用程序。
ANR 产生的原因
只有应用程序的 UI 线程响应超时才会引起 ANR,超时产生原因一般有两种。
当前的事件没有机会得到处理,例如 UI 线程正在响应另外一个事件,当前事件由于某种原因被阻塞了。
当前事件正在处理,但是由于耗时太长没能及时完成。
根据 ANR 产生的原因不同,超时时间也不尽相同,从本质上讲,产生 ANR 的原因有三种,大致可以对应到 Android 中的四大组件的三个(Activity/View,BroadcastReceived 和 Service)。
KeyDispatchTimeout,原因是 View 的按钮事件或者触摸事件在特定的事件(5秒)内无法得到响应。
BroadcastTimeout,原因是 BroadcastReceived 的 onReceived 函数运行在主线程中,在特定的事件(10秒)内无法完成处理。
ServiceTimeout,原因是 Service 的各个生命周期函数在特定事件(20秒)内无法完成处理。
典型的 ANR 问题场景
应用程序 UI 线程存在耗时操作,例如在 UI 线程中进行网络请求,数据库操作或者文件操作,可能导致 UI 线程无法及时处理用户输入等。在 Android 之后,如果在 UI 线程中进行网络操作,将会抛出 NetworkOnMainThreadException 异常。
应用程序的 UI 线程等待子线程释放某个锁,从而无法处理用户的输入。
耗时的动画需要大量的计算工作,可能导致 CPU 负载过重。
降低ANR出现的频率
降低 ANR 出现的频率,尊重一个原则:
不要在主线程做繁重的任务。
避免在主线程读取数据。Andrioid 禁止在主线程从网络读数据,但是没有禁止从本地数据库或者其他地方获取数据,这种操作 ANR 风险很大,也会造成丢帧。
sharePreference 是全量更新而不是增量更新,所以尽量统一 apply,并且存储的文件不宜过大,过大的文件可以考虑写入到文件或者本地的数据库中。
不要在 BroadcastReceived 的 onRecieve 中干活,可以选择开个 IntentService 去执行响应操作。
各个组件的生命周期不应该有太过耗时的操作。
尽量避免主线程的被锁的情况,在一些同步操作中可能出现主线程被锁的情况,这样会有一定的 ANR 风险。
避免一次性价值大量的大图高清图。