ANR详解
1:
当用户点击屏幕时,系统会生成一个 MotionEvent
并回调相应 View
的 onTouchEvent
方法。如果在 onTouchEvent
方法中执行耗时操作,会导致主线程的 Looper
被阻塞,无法及时处理接下来的事件或消息。如果这种阻塞持续超过 5 秒,系统会认为应用程序没有响应,从而触发 ANR(Application Not Responding)弹窗。
这种情况下,表现为在主线程处理当前触摸事件时,无法及时响应后续的用户点击操作或者其他通过 Handler
发送的消息。
为了避免 ANR,主线程(UI 线程)应该尽量避免执行耗时操作。当 Looper
从 MessageQueue
中取出一个消息(Message)时,如果该消息需要进行耗时处理,应该将这些操作移到子线程中执行。这样可以确保主线程能够迅速处理下一个消息,保持应用的响应性,避免 ANR 弹窗的出现。
在 Android 中,可以使用 AsyncTask
、HandlerThread
、ExecutorService
等工具将耗时操作移到后台线程中执行,同时通过 Handler
将结果传回主线程以更新 UI。这样可以有效避免主线程被阻塞,提高应用的流畅度和用户体验。
总结起来:
- ANR 触发原因:主线程被阻塞超过 5 秒,导致无法处理后续的事件或消息。
- 避免方法:将耗时操作移到后台线程,保持主线程的轻量级和高响应性。
- 实现工具:使用
AsyncTask
、HandlerThread
、ExecutorService
等工具执行后台任务,通过Handler
更新 UI。
通过这些措施,可以确保主线程快速响应用户输入和系统事件,从而避免 ANR 的发生。
ANR 触发机制
-
第一个输入事件:
- 用户产生第一个输入事件(例如,点击屏幕)。
- 系统将该事件发送给应用并调用相应的处理方法(如
onTouchEvent
)。
-
第二个输入事件:
- 用户产生第二个输入事件。
- 系统记录第一个事件的处理时间是否超过 0.5 秒。
- 如果第一个事件超过 0.5 秒还未处理完,系统会设置一个定时器,5 秒后触发检查。
-
定时器触发:
- 5 秒后,定时器触发,系统检查第一个事件是否已经处理完毕。
- 如果第一个事件仍未处理完毕,系统认为应用没有响应,触发 ANR。
关键点
- 第一个事件的处理时间:第一个输入事件必须在 5.5 秒以上(0.5 秒 + 5 秒定时器)没有被处理完成并反馈回系统。
- 第二个输入事件的存在:需要有第二个输入事件产生,系统才能开始计时和触发 ANR。
本质分析
-
第一个事件的阻塞:本质上,ANR 的触发是由于第一个事件在长时间内(5.5 秒以上)没有被处理完成。第二个事件的存在只是一个触发条件,用来启动定时器和后续的 ANR 机制。
-
第二个事件的作用:第二个事件的主要作用是告诉系统第一个事件已经处理时间过长,从而开始计时。如果没有第二个事件,系统不会意识到第一个事件的处理时间过长,也就不会触发 ANR。
-
主线程阻塞:如果主线程被一个耗时操作长时间阻塞,无论有多少输入事件,最终都会导致无法响应后续的输入事件,从而触发 ANR。