主线程中runBlocking与launch执行超5秒未触发ANR的原因?
问题
通常Android主线程执行耗时超5秒的操作会触发ANR错误,但在Activity的onCreate方法中,使用runBlocking和launch在主线程执行了循环500次、每次休眠50ms的耗时任务(总耗时超25秒),却未触发ANR错误。以下是代码片段及运行日志,请求解答该现象的原因:
代码片段
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_coroutine) Log.d("test", "Main program started ${Thread.currentThread().name}") runBlocking { Log.d("test", "run blocking ${Thread.currentThread().name}") var job = launch { Log.d("test", "launch: ${Thread.currentThread().name}") for(i in 1..500){ println("$i...") Thread.sleep(50) } } job.join() Log.d("test","Main program ended ${Thread.currentThread().name}") } Log.d("test","activity oncreate() ended ${Thread.currentThread().name}") }
运行日志
Main program started the main run blocking the main launch: main 1.. 2.. ... 500 Main program ended Mainactivity oncreate() ended main
原因分析
- ANR的触发逻辑:Android系统触发ANR的核心判定标准是主线程是否无法及时处理消息队列中的事件(比如输入事件、广播、服务请求),检测动作只会在主线程的消息循环空闲时执行。只有当主线程在消息循环阶段被长时间阻塞,无法响应系统事件时,才会触发ANR。
- 生命周期方法的执行阶段特性:你的耗时任务完全在
onCreate方法执行过程中完成,此时主线程正处于Activity初始化的同步执行流程里,还没进入到「主线程消息循环处理系统事件」的阶段。系统还未开始监控主线程的消息循环卡顿情况,自然不会判定ANR。 runBlocking的作用:runBlocking会直接阻塞当前线程(这里就是主线程),但它的阻塞发生在onCreate的执行流程内,而非主线程消息循环的事件处理阶段。只有当onCreate执行完毕,主线程回到消息循环开始处理各类系统事件后,长时间阻塞才会触发ANR。- 协程上下文的误区:这里的
launch没有指定Dispatcher,默认继承runBlocking的上下文(也就是主线程),所以任务确实在主线程执行,但因为处于Activity生命周期方法的同步执行阶段,不在ANR检测的时间窗口内,因此不会触发ANR。
内容的提问来源于stack exchange,提问作者Sai
相关产品推荐
相关产品推荐

