Kotlin协程:为什么这不引发NetworkOnMainThreadException?

时间:2019-03-18 14:30:13

标签: android kotlin kotlin-coroutines

client使用翻新协程适配器。

我不明白,为什么我没有得到NetworkOnMainThreadException? 是不是在主线程上调用了?

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val deferred = client.getStuffDeferred(file)
    CoroutineScope(Dispatchers.Main).launch {
        val response = deferred.await()
    }
}

3 个答案:

答案 0 :(得分:0)

使用 Retrofit Coroutines适配器,并且Retrofit函数返回DefferedCall对象时,该请求将在工作线程(后台)中执行。在协程中调用标记为deferred.await()的函数suspend可以挂起协程,而不会阻塞UI线程。这意味着您可以等待请求完成并更新UI,而不会引发NetworkOnMainThreadException异常:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val deferred = client.getStuffDeferred(file)
    CoroutineScope(Dispatchers.Main).launch {
        val response = deferred.await() // wait until request is executed in a background thread without blocking the Main Thread
        // update UI
    }
}

答案 1 :(得分:0)

如果您将协程上下文传递给协程生成器,则此类协程将使用该线程执行。

  1. Dispatchers.Default –如果在其上下文中未指定调度程序或任何其他ContinuationInterceptor,则供所有标准构建器使用。它使用共享后台线程的公共池。对于消耗CPU资源的计算密集型协程,这是一个合适的选择。
  2. Dispatchers.IO –使用按需创建的线程共享池,并用于卸载IO密集型阻塞操作(如文件I / O和阻塞套接字I / O)。 / li>
  3. Dispatchers.Unconfined –在当前调用框架中开始协程执行,直到第一次暂停。第一次暂停时,协程生成器函数返回。协程可以在相应的挂起函数使用的任何线程中恢复,而不必将其限制在任何特定的线程或池中。无限制调度程序通常不应在代码中使用。
  4. 可以使用newSingleThreadContextnewFixedThreadPoolContext创建专用线程池。
  5. 可以使用Executor扩展功能将任意asCoroutineDispatcher转换为调度程序。

因此,使用类似:

CoroutineScope(Dispatchers.IO).launch { // we should use IO thread here !

}

答案 2 :(得分:0)

如果在Dispatchers.Main上调用launch,它将在主线程上运行,但会暂停执行以免阻塞线程。

因为您的CoroutineScope中没有挂起方法或runBlocking方法,所以此行为不会阻止或引发NetworkOnMainThreadException

但是: 您应该在进行网络操作或进行任何繁重的操作时更改上下文,使用

可能会减慢您的UI线程操作
withContext(Dispatchers.IO){// your suspended calls}

,您可以将当前上下文更改为后台线程,并在主线程中继续工作而没有任何问题

在solution3上看看这个article 使用协程