MainScope 与 GlobalScope

MainScope vs GlobalScope

提问人:Bitwise DEVS 提问时间:12/3/2021 更新时间:12/3/2021 访问量:5915

问:

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 有时会犯一个很难重现的错误。

致命异常: android.view.ViewRootImpl$CalledFromWrongThreadException:仅 创建视图层次结构的原始线程可以触摸其视图。

MainScope().launch {
            var storeName = ""
            withContext(Dispatchers.Default) {
                storeName = pfViewModel.getStoreName()
            }
            v.tvStoreName.text = storeName
        }
Android Kotlin Kotlin-协程

评论


答:

14赞 Joffrey 12/3/2021 #1

GlobalScope 和 MainScope 有什么区别?

MainScope是默认使用调度程序的,调度程序绑定到主 UI 线程。CoroutineScopeDispatchers.Main

是在其协程上下文中没有调度程序的 a。这意味着在此作用域中启动的协程将使用调度程序,该调度程序由线程池(根据您拥有的 CPU 内核数调整大小)提供支持。GlobalScopeCoroutineScopeDispatchers.Default

在其上下文中也没有,这意味着结构化并发不适用。其中启动的协程永远不会自动取消,因此需要手动控制。这就是为什么除非您有非常具体的需求,否则通常不鼓励使用它。GlobalScopeJob

只有创建视图层次结构的原始线程才能触及其视图。

当您尝试从主线程外部修改视图时,会发生此错误,如果您从 中启动的协程执行此操作,则会发生这种情况(因为它由单独的线程池支持)。GlobalScope

在第二个代码片段中,您使用的是 ,它仅使这部分代码在该线程池上运行,但其余部分在 UI 线程上运行。这就是为什么那里的UI更新是可以的。withContext(Dispatchers.Default)

请注意,Room 已经使用带有后台线程池的调度程序进行查询,因此您不需要像这样手动切换上下文,只需从 UI 线程调用它即可。

旁注:像这样使用是一个坏主意,因为它与 .为了正确使用它,您需要将此范围提取到变量/属性中,以便在适当的时候取消它。也就是说,使用现有范围更容易。Android 已经在具有生命周期的 Activity 等组件中提供了现成的协程范围(请参阅库)。它被称为 .您应该在此范围内启动协程,以便在销毁活动时自动取消协程。MainScope().launch { .. }GlobalScopelifecycle-runtime-ktxlifecycleScope

评论

0赞 Bitwise DEVS 12/3/2021
换句话说,我最好在这个中使用 lifecycleScope,对吗?出于某种原因,此项目中 Room 的当前实现不允许访问数据,因为它位于主线程中。
0赞 Joffrey 12/3/2021
是的,您应该更喜欢(或取决于您所在的组件)lifecycleScopeviewModelScope
0赞 Bitwise DEVS 1/20/2022
后续问题,如果我不在任何范围内,例如 nor 怎么办?就像协程是在自定义视图库上实现的一样?viewModelScopelifecycleScope
0赞 Joffrey 1/20/2022
通常,在这种情况下,最好使用挂起函数或流。但是,如果您确实需要启动长期协程,则可以创建一个自定义范围,您可以使用自定义类具有的任何生命周期适当地取消该范围。