【问题标题】:Returning value from normal function which called suspend function using Kotlin Coroutine从使用 Kotlin 协程调用挂起函数的普通函数返回值
【发布时间】:2019-10-10 01:50:42
【问题描述】:

您好,我在一个项目中使用 Kotlin 协程库。

下面的方法调用一个挂起函数,它返回一个布尔值。

fun isNetworkAvailable(context: Context?): Boolean {
            //return checkNetworkReachability(context)
            var isNetworkAvailable = false
            GlobalScope.launch(Dispatchers.Default) {
                isNetworkAvailable = GlobalScope.async<Boolean> {
                    checkNetwork()

                }.await()
            }
            return isNetworkAvailable

        }

这里的 checkNetwork 是挂起函数。在执行它之前,返回值被传递给调用者(视图/活动)。 如果不将“isNetworkAvailable”设为挂起,我该如何实现?

在 checkNetwork 方法中,检查调用网络调用的可达性,如下所示。

private suspend fun checkNetwork() : Boolean {
            val value = GlobalScope.async<Boolean> {
                val isEastReachable = async { checkEastReachable() }
                if (!isEastReachable.await()) {
                    checkWestReachable()
                } else {
                    true
                }
            }

            return value.await()
        }

而子方法是

private suspend fun checkEastReachable(): Boolean = coroutineScope {

                withContext(Dispatchers.Default) {
                    repository.networkManager.callReachableEast()
                }
            }



private suspend fun checkWestReachable(): Boolean = coroutineScope {

                withContext(Dispatchers.Default) {
                    repository.networkManager.callReachableWest()
                }
            }

子挂起方法正在使用改造调用 Web 服务。因为它会返回一个布尔值,所以我将它作为一个同步的 .execute() 调用。

fun callReachableEast(): Boolean {
        return try {
            val requestCall =
                ApiService.create("eastApi").getReachabilityEast()
            requestCall.execute().isSuccessful
        } catch (exception: Exception) {
            false
        }
    }

    fun callReachableWest(): Boolean {
        return try {
            val requestCall =
                ApiService.create("westApi").getReachabilityWest()
            return requestCall.execute().isSuccessful
        } catch (exception: Exception) {
            false
        }
    }

我已经浏览了以下链接

https://kotlinlang.org/docs/reference/coroutines/composing-suspending-functions.html

https://proandroiddev.com/async-operations-with-kotlin-coroutines-part-1-c51cc581ad33

还有更多。

重复我的问题,如果不将“isNetworkAvailable”设置为挂起,我该如何实现?

【问题讨论】:

  • 什么意思~"在执行之前将返回值传递给调用者"

标签: android kotlin async-await kotlin-coroutines coroutinescope


【解决方案1】:

如果你不能让isNetworkAvailable 成为suspend 函数,那么它将是一个阻塞函数。这意味着,任何调用 isNetworkAvailable 的代码也会阻塞,或者您需要更改此函数的签名以改为使用回调。

首先,让我们看一下阻塞版本。有一个特殊的协程构建器适用于从可挂起的世界桥接到常规/阻塞的世界。它被称为runBlocking

fun isNetworkAvailable(context: Context?): Boolean = runBlocking {
    checkNetworkReachability(context)
}

...

val isAvailable = isNetworkAvailable(activity)
if (isAvailable) { ... }
...

如果您想更改其签名并使用回调而不是返回值:

fun CoroutineScope.isNetworkAvailable(context: Context?, callback: (Boolean) -> Unit) { 
    launch {
        callback(checkNetworkReachability(context))
    }
}

...
scope.isNetworkAvailable(activity) { isAvailable ->
    if (isAvailable) { ... }
}

(代码可能有错别字)

【讨论】:

  • 是的,我通过阻塞 (runBlocking) 实现了。将尝试回调。
  • 我们应该在Android UI层使用runBlocking吗?
  • @IgorGanapolsky 不。永远不要直接从主 UI 线程调用 runBlocking。
  • @StreetsOfBoston 很高兴包含替代方案并证明为什么您不会在 UI 线程中调用它,只是对稍后阅读它的其他人说。请提供更多信息。
猜你喜欢
  • 1970-01-01
  • 2019-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-20
  • 1970-01-01
  • 1970-01-01
  • 2018-06-15
相关资源
最近更新 更多