Kotlin协程切换至Dispatchers.Main失效,withContext代码不执行求助
问题场景
我编写了如下Kotlin协程代码:
coroutineScope.launch(Dispatchers.IO) { if (openGraphParser != null && isActive) { Logger.info("Loading OpenGraph data for $link") val content = openGraphParser.getContents(link, messageText) Logger.info("OpenGraph data for $link received") withContext(Dispatchers.Main) { Logger.info("Showing OpenGraph data for $link") onOgDataReceived(content) } } }
但未看到日志“Showing OpenGraph data for $link”,withContext(Dispatchers.Main)中的代码完全未执行,最后输出的日志停留在“OpenGraph data for $link received”。
当我将代码修改为通过View的post方法执行时,所有功能均可正常运行:
coroutineScope.launch(Dispatchers.IO) { if (openGraphParser != null && isActive) { Logger.info("Loading OpenGraph data for $link") val content = openGraphParser.getContents(link, messageText) Logger.info("OpenGraph data for $link received") ogDataContent?.ogDataLayout?.get()?.post { Logger.info("Showing OpenGraph data for $link") onOgDataReceived(content) } } }
请问这是什么原因导致的?
原因分析
Main调度器依赖的主线程Looper失效
Android中的Dispatchers.Main绑定主线程Looper工作,如果当前页面(Activity/Fragment)已经销毁,或者主线程Looper出现异常终止,协程切换到Main调度器时会因为找不到有效的执行上下文,直接跳过这部分代码。而View.post()依托View自身关联的Looper,只要View还未被完全销毁(仍关联着有效的Window),就能正常获取主线程Looper执行任务。coroutineScope已被取消
如果你使用的是页面生命周期绑定的Scope(比如lifecycleScope或viewLifecycleOwner.lifecycleScope),当页面走到销毁阶段时,该Scope会被自动取消。在withContext(Dispatchers.Main)执行前,如果Scope已经取消,协程会直接终止后续代码执行。而View.post()属于Android View体系的消息机制,不受协程Scope取消状态的影响,只要View存活就能执行。Main调度器任务队列阻塞(概率较低)
若主线程消息队列被耗时操作阻塞,withContext(Dispatchers.Main)提交的任务会一直排队无法执行。但这种情况不会导致代码完全不执行,只是延迟,所以更可能是前两种原因。
内容的提问来源于stack exchange,提问作者Vladimir Fisher

