【问题标题】:Confusing about Kotlin Coroutines execution: where to call await()?对 Kotlin Coroutines 执行感到困惑:在哪里调用 await()?
【发布时间】:2019-10-14 16:14:00
【问题描述】:

我阅读了很多关于 Kotlin 协程的文档,但仍有一些疑问。我将 Retrofit 与协程一起使用,因此我需要使用 Dispatchers.IO 上下文进行请求,但使用 Dispatchers.Main 上下文中的结果将其分配给 ViewModel。我的代码是:

fun doHttpreq() {
    viewModelScope.launch(Dispatchers.IO) {
        try {
            //should I call await() here? (I guess the correct way to keep execution of request outside of Main thread)
            val request = RestClient.instance.getItems().await()

            withContext(Dispatchers.Main) {
                //or should I call await() here? (BUT need request to be executed outside of Main thread!)

                if (request.isSuccessful) {
                   //asign items to ViewModel

                } else {
                    //asign error to ViewModel
                }
            }

        } catch (e: Exception) {
            withContext(Dispatchers.Main) {
                //asign error to ViewModel
            }
        }
    }
}

【问题讨论】:

标签: android kotlin retrofit


【解决方案1】:

您可以在变量中接受您的延期工作,然后在您的 主调度员 上等待它,如下所示:

try {
        //Rather than await here, you take your Job as Deffered
        val request: Deferred? = RestClient.instance.getItems()

        withContext(Dispatchers.Main) {
            //Yes, you can await here because it's non-blocking call and can be safely obtained from here once completed
            val result = request?.await()
            if (request.isSuccessful) {
               //asign items to ViewModel

            } else {
                //asign error to ViewModel
            }
        }

    } catch (e: Exception) {
        withContext(Dispatchers.Main) {
            //asign error to ViewModel
        }
    }

官方文档对await() 的描述:

等待这个值的完成不阻塞线程并在延迟计算完成时恢复,返回结果值抛出相应的异常 如果延期被取消了。

这个暂停功能是可以取消的。如果当前协程的 Job 在此挂起函数等待期间被取消或完成,则此函数立即以 CancellationException 恢复。

此函数可用于带有 onAwait 子句的 select 调用。使用 isCompleted 无需等待即可检查此延迟值是否完成。

【讨论】:

    【解决方案2】:

    由于协程是挂起而不是阻塞,因此不需要管理它们正在运行的线程。在您的情况下,Retrofit 会为您处理这个问题。此外Deferred 类型实际上是一个热数据源。这意味着 Call 在您调用 await 之前就已执行。 await 只是等待数据在那里。

    因此,您可以直接在 Main 调度程序上启动。因此,您只有一个地方可以拨打await()

    viewModelScope.launch(Dispatchers.Main) {
        try {
            val request = RestClient.instance.getItems().await()
    
            if (request.isSuccessful) {
                //asign items to ViewModel
            } else {
                //asign error to ViewModel
            }
        } catch (e: Exception) {
            //asign error to ViewModel
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-05
      • 2011-06-01
      • 2015-07-29
      • 2017-02-03
      • 1970-01-01
      • 1970-01-01
      • 2021-01-13
      • 1970-01-01
      相关资源
      最近更新 更多