GlobalScope和MainScope之间有什么区别?
MainScope
是
CoroutineScope
使用
Dispatchers.Main
默认情况下,它绑定到主UI线程。
这个
GlobalScope
是
CoroutineScope
在其协同程序上下文中没有调度器。这意味着在此范围内启动的协同程序将使用
Dispatchers.Default
调度器,它由一个线程池(根据您拥有的CPU核的数量来确定大小)支持。
这个
GlobalScope
也没有
Job
在其上下文中,这意味着结构化并发不适用。在其中启动的Coroutines永远不会自动取消,因此需要手动控制。这就是为什么除非你有非常具体的需求,否则通常不鼓励使用它。
只有创建视图层次结构的原始线程才能接触其视图。
当您试图从主线程外部修改视图时,就会发生此错误,如果您从
GlobalScope
(因为它由一个单独的线程池支持)。
在第二个片段中,您使用
withContext(Dispatchers.Default)
,这只会使这部分代码在该线程池上运行,而其余代码则在UI线程上运行。这就是为什么UI的更新是可以的。
请注意,Room已经使用了一个带有后台线程池的调度器来进行查询,因此您不需要像这样手动切换上下文,只需从UI线程调用即可。
旁注:使用
MainScope().launch { .. }
这样做是个坏主意,因为它与
GlobalScope
。要正确使用它,您需要将此作用域提取到变量/属性中,以便在适当的时候取消它。也就是说,使用现有范围更容易。安卓
already provides a ready-to-use coroutine scope
在组件中,如具有生命周期的“活动”(请参阅
lifecycle-runtime-ktx
图书馆它被称为
lifecycleScope
。你应该在这个范围内启动协同程序,这样当活动被破坏时,它们就会自动被取消。