MainScope 与 GlobalScope
MainScope vs GlobalScope
GlobalScope 和 MainScope 有什么区别?
//Accessing data from Room
GlobalScope.launch {
v.tvStoreName.text = pfViewModel.getStoreName()
pageDetails.pageNumber = currentPage
pageDetails.pageSize = pageSize
pfViewModel.getTransactions(pageDetails, toolbarBuilder?.getDate()!!)
}
GlobalScope 有时会出现很难重现的错误。
Fatal Exception:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the
original thread that created a view hierarchy can touch its views.
MainScope().launch {
var storeName = ""
withContext(Dispatchers.Default) {
storeName = pfViewModel.getStoreName()
}
v.tvStoreName.text = storeName
}
What is the difference between GlobalScope and MainScope?
MainScope
是默认使用 Dispatchers.Main
调度程序的 CoroutineScope
,它绑定到主 UI 线程。
GlobalScope
是一个 CoroutineScope
,在其协程上下文中没有调度程序。这意味着在此范围内启动的协程将使用 Dispatchers.Default
调度程序,该调度程序由线程池支持(大小取决于您拥有的 CPU 核心数)。
GlobalScope
在其上下文中也没有 Job
,这意味着结构化并发不适用。其中启动的协程永远不会自动取消,所以需要手动控制。这就是为什么通常不鼓励使用它,除非您有非常特殊的需求。
Only the original thread that created a view hierarchy can touch its views.
当您尝试从主线程外部修改视图时会发生此错误,如果您从 GlobalScope
中启动的协程执行此操作(因为它由单独的线程池支持),就会发生这种情况.
在您的第二个代码段中,您使用的是 withContext(Dispatchers.Default)
,这只会使该线程池中的这部分代码 运行,而其余 运行 则在 [=45] =] 线程。这就是 UI 更新在那里的原因。
请注意,Room 已经为其查询使用了一个带有后台线程池的调度程序,因此您不需要像这样手动切换上下文,您可以从 UI 线程中调用它。
旁注:像这样使用 MainScope().launch { .. }
不是一个好主意,因为它遇到与 GlobalScope
相同的取消问题。要正确使用它,您需要将此范围提取到 variable/property 中,以便您可以在适当的时候取消它。也就是说,使用现有范围更容易。 Android already provides a ready-to-use coroutine scope 在组件中,例如具有生命周期的活动(请参阅 lifecycle-runtime-ktx
库)。它被称为 lifecycleScope
。您应该在此范围内启动协程,以便在 activity 被销毁时它们会自动取消。
GlobalScope 和 MainScope 有什么区别?
//Accessing data from Room
GlobalScope.launch {
v.tvStoreName.text = pfViewModel.getStoreName()
pageDetails.pageNumber = currentPage
pageDetails.pageSize = pageSize
pfViewModel.getTransactions(pageDetails, toolbarBuilder?.getDate()!!)
}
GlobalScope 有时会出现很难重现的错误。
Fatal Exception: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
MainScope().launch {
var storeName = ""
withContext(Dispatchers.Default) {
storeName = pfViewModel.getStoreName()
}
v.tvStoreName.text = storeName
}
What is the difference between GlobalScope and MainScope?
MainScope
是默认使用 Dispatchers.Main
调度程序的 CoroutineScope
,它绑定到主 UI 线程。
GlobalScope
是一个 CoroutineScope
,在其协程上下文中没有调度程序。这意味着在此范围内启动的协程将使用 Dispatchers.Default
调度程序,该调度程序由线程池支持(大小取决于您拥有的 CPU 核心数)。
GlobalScope
在其上下文中也没有 Job
,这意味着结构化并发不适用。其中启动的协程永远不会自动取消,所以需要手动控制。这就是为什么通常不鼓励使用它,除非您有非常特殊的需求。
Only the original thread that created a view hierarchy can touch its views.
当您尝试从主线程外部修改视图时会发生此错误,如果您从 GlobalScope
中启动的协程执行此操作(因为它由单独的线程池支持),就会发生这种情况.
在您的第二个代码段中,您使用的是 withContext(Dispatchers.Default)
,这只会使该线程池中的这部分代码 运行,而其余 运行 则在 [=45] =] 线程。这就是 UI 更新在那里的原因。
请注意,Room 已经为其查询使用了一个带有后台线程池的调度程序,因此您不需要像这样手动切换上下文,您可以从 UI 线程中调用它。
旁注:像这样使用 MainScope().launch { .. }
不是一个好主意,因为它遇到与 GlobalScope
相同的取消问题。要正确使用它,您需要将此范围提取到 variable/property 中,以便您可以在适当的时候取消它。也就是说,使用现有范围更容易。 Android already provides a ready-to-use coroutine scope 在组件中,例如具有生命周期的活动(请参阅 lifecycle-runtime-ktx
库)。它被称为 lifecycleScope
。您应该在此范围内启动协程,以便在 activity 被销毁时它们会自动取消。