从使用 Kotlin 协程调用挂起函数的普通函数返回值

Kar*_* Ve 4 android async-await kotlin kotlin-coroutines coroutinescope

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

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

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

                }.await()
            }
            return isNetworkAvailable

        }
Run Code Online (Sandbox Code Playgroud)

这里的 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()
        }
Run Code Online (Sandbox Code Playgroud)

子方法是

private suspend fun checkEastReachable(): Boolean = coroutineScope {

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



private suspend fun checkWestReachable(): Boolean = coroutineScope {

                withContext(Dispatchers.Default) {
                    repository.networkManager.callReachableWest()
                }
            }
Run Code Online (Sandbox Code Playgroud)

子挂起方法正在使用改造调用 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
        }
    }
Run Code Online (Sandbox Code Playgroud)

我已经浏览了以下链接

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

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

还有一些。

重复我的问题,如何在不将“isNetworkAvailable”设为挂起的情况下实现?。

Str*_*ton 5

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

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

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

...

val isAvailable = isNetworkAvailable(activity)
if (isAvailable) { ... }
...
Run Code Online (Sandbox Code Playgroud)

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

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

...
scope.isNetworkAvailable(activity) { isAvailable ->
    if (isAvailable) { ... }
}
Run Code Online (Sandbox Code Playgroud)

(代码可能有错别字)

  • @IgorGanapolsky 不。永远不要直接从主 UI 线程调用 runBlocking。 (3认同)
  • @StreetsOfBoston,最好包含替代方案并证明为什么您不会在 UI 线程中调用它,只是为稍后阅读它的其他人说。请提供更多相关信息。 (2认同)