代码之家  ›  专栏  ›  技术社区  ›  Bitwise DEVS

MainScope与GlobalScope

  •  0
  • Bitwise DEVS  · 技术社区  · 3 年前

    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
            }
    
    1 回复  |  直到 3 年前
        1
  •  9
  •   Joffrey    3 年前

    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 。你应该在这个范围内启动协同程序,这样当活动被破坏时,它们就会自动被取消。