Android主线程进行 Thread.Sleep()会导致AN
首先 先 明白一个问题:什么是ANR
Application Not Responding,意思是”应用没有响应“
以前我的理解就是 “在主线程做了耗时操作”就会引起ANR,现在我觉得我是错误的,ANR的意思是应用没有响应,耗时操作实际上 并不一定会导致没有响应,我对没有响应的理解是
有人(事件或操作)发出了一个请求,但是主线程没有对这个人进行反馈(可能是没时间、可能是不想理、可能是手被绑住了没有办法理你),这个叫没有响应
那举个例子
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// do some blablabla...
Log.d("test", "准备sleep30秒")
Thread.sleep(30000)
Log.d("test", "sleep30秒完成")
// do some blablabla...
}
这段代码在 onCreate 中 sleep 了 30秒,会出现 ANR 吗?
答案是
可能会,也可能不会
当主线程在 Sleep 的时候,如果 UI线程不需要进行操作,也就是说没有消息会发送给UI线程并要求UI线程进行处理的时候 Sleep 30秒就不会导致ANR,因为没有 出现 ANR(应用没有响应)的情况啊,没有人向线程请求什么东西,也就不需要响应了,既然没有响应了,那怎么会有ANR呢?
但是,但线程在Sleep的时候,主线程有接收到需要处理的请求的时候
需要注意的是,需要处理的请求,不一定只是用户的手动触摸,也有可能是其他线程需要对线程进行UI更新的请求,这个时候UI线程正在Sleep,根本没有办法理你(不想理你),这就符合了ANR的条件,所以会出现ANR(比如说在这 30 秒内,点击了 返回按钮,就会出现 ANR)
另外,如果在这个30秒内进行UI更新会发生ANR吗?
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Handler().postDelayed(Runnable {
Log.d("sleep_test", "准备更新text")
btn_test.text = "update btn text"
Log.d("sleep_test", "更新text完成")
}, 10000)
Log.d("sleep_test", "准备sleep30秒")
Thread.sleep(30000)
Log.d("sleep_test", "sleep30秒完成")
Log.d("sleep_test", "first update")
btn_test.text = "This is the first update"
}
输出结果为:
D/sleep_test: 准备sleep30秒
D/sleep_test: sleep30秒完成
D/sleep_test: first update
D/sleep_test: 准备更新text
D/sleep_test: 更新text完成
并没有发生ANR,这是因为这段代码里面的sleep休眠了线程,代码里面的更新操作根本没有在 sleep的时候被触发(处于休眠状态),也就没有了发送请求的前提条件,所以并没有发生ANR。但是如果用户手动进行了触摸操作,相当于有一个请求的事件了,而主线程又被休眠了,超过了规定的时间就会触发ANR提示
在android里面都对其进行了常量定义
Android N 的 ANR时间
- Service 超时
// How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20*1000; // 前台
// How long we wait for a service to finish executing.
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10; // 后台
- Broadcast 超时
// How long we allow a receiver to run before giving up on it.
static final int BROADCAST_FG_TIMEOUT = 10*1000; // 前台
static final int BROADCAST_BG_TIMEOUT = 60*1000; // 后台
- InputDispatching 超时
// How long we wait until we timeout on key dispatching.
static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
- ContentProvider 超时
// How long we wait for an attached process to publish its content providers
// before we decide it must be hung.
static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;
ANR的学习目前就到这个点,后续还要继续学习
延伸:Thread.sleep() 还有其加锁的问题
由于CPU分配的每个线程的时间片极为短暂(一般为几十毫秒),所以,CPU通过不停地切换线程执行,这样就给程序员一种错觉,以为多个线程是在同时执行。sleep就是正在执行的线程主动让出CPU,CPU去执行其他线程,在sleep指定的时间过后,CPU才会回到这个线程上继续往下执行。
已发布至: jimbray