【问题标题】:How to call suspend function from another suspend function without blocking caller function?如何在不阻塞调用者函数的情况下从另一个挂起函数调用挂起函数?
【发布时间】:2020-11-26 07:55:40
【问题描述】:

我正在从一个挂起函数调用一个 Api,在成功执行它之后,我需要调用另一个 Api(它也在另一个挂起函数中)。

    suspend fun updateSubscription(body: Map<String, Any>): NetworkResponse<SubscriptionUpdateResponse> =
        withContext(Dispatchers.IO) {
            val response = networkManager.execute(
                networkManager.updateSubscriptionApi(body)
            )
            val data = response.body()
            if (response.isSuccessful) {
                fetchSubscriptions() // suspend function which call another api, should run without blocking
            }
            return@withContext parseNetworkResponse(response, data)
        }

我想调用updateSubscriptionApi,在它成功执行后,不阻塞地调用fetchSubscription并返回updateSubscription结果。

目前,fetchSubscription 也在阻止 updateSubscription。我尝试像这样在async 块中调用updateSubscription,但没有成功。

async{ updateSubscription() }

如何在不阻塞updateSubscription的情况下拨打fetchSubscriptions()

【问题讨论】:

    标签: kotlin asynchronous kotlin-coroutines suspend


    【解决方案1】:

    不幸的是,您对函数的要求是在函数返回时暂停和启动仍然处于活动状态的并发工作,这在 Kotlin 中被认为是一种反模式,并且难以实现。

    但首先,简单的事情:

    1. 您确定需要IO 调度程序吗?您说网络调用处于挂起状态,这意味着非阻塞,不需要专用的 IO 调度程序。

    2. 如果您确实需要它(它实际上是一个阻塞调用),请不要将所有代码都包含在其中,而只是该调用。

    现在,最困难的部分。为了能够启动协程,考虑在哪个范围内启动它至关重要。Kotlin 强烈建议使用结构化并发,这意味着在 UI 元素(活动等)的明确定义范围内启动所有内容.在您的情况下,您必须将范围作为参数显式传递给函数。通常你会将它声明为CoroutineScope 上的扩展,但由于coroutineContext 上的命名冲突,这对于挂起函数不起作用,这既是全局val 也是CoroutineScope 的属性。这意味着您的代码可能如下所示:

    import kotlinx.coroutines.CoroutineScope
    import kotlinx.coroutines.Dispatchers
    import kotlinx.coroutines.launch
    import kotlinx.coroutines.withContext
    
    suspend fun updateSubscription(
            scope: CoroutineScope,
            body: Map<String, Any>
    ): NetworkResponse<SubscriptionUpdateResponse> {
        val response = withContext(Dispatchers.IO) { // only if you need it!
            networkManager.execute(networkManager.updateSubscriptionApi(body))
        }
        if (response.isSuccessful) {
            scope.launch { fetchSubscriptions() }
        }
        return parseNetworkResponse(response, response.body())
    }
    

    【讨论】:

    • 是的,我需要 IO 调度员,因为我的电话被阻塞了。我已经尝试过你的解决方案,它对我有用。谢谢
    猜你喜欢
    • 2021-11-03
    • 2020-06-27
    • 2020-11-07
    • 1970-01-01
    • 2019-05-24
    • 2021-09-29
    • 2020-04-13
    • 2020-07-19
    • 1970-01-01
    相关资源
    最近更新 更多