3

我更改了问题标题,因为Kiskae 为更广泛的问题提供了解决方案,这使得关于包装回调 API 的问题对于特定问题来说是不必要的。以前的问题标题是:

如何使用协程将异步回调包装到挂起函数中?


我正在尝试将ConnectivityManager.NetworkCallbackAndroid 框架的 API(>= SDK 级别 21)包装到挂起函数中,以促进同步 API:

private suspend fun ConnectivityManager.isNetworkAvailable(
    vararg transportType: /* android.net.NetworkCapabilities.Transport */ Int)
: Boolean {
    val isAvailable = suspendCancellableCoroutine<Boolean> { continuation ->
        val builder = NetworkRequest.Builder()
        transportType.forEach {
            builder.addCapability(it)
        }
        val networkRequest = builder.build()
        val networkCallback = object : ConnectivityManager.NetworkCallback() {
            override fun onAvailable(network: Network) {
                super.onAvailable(network)
                Log.d(javaClass.simpleName, "[${Thread.currentThread().name}] onAvailable")
                continuation.resume(true)
                unregisterNetworkCallback(this)
            }

            override fun onLost(network: Network) {
                super.onLost(network)
                Log.d(javaClass.simpleName, "[${Thread.currentThread().name}] onLost")
                continuation.resume(false)
                unregisterNetworkCallback(this)
            }
        }
        Log.d(javaClass.simpleName, "[${Thread.currentThread().name}] registerNetworkCallback BEFORE")
        registerNetworkCallback(networkRequest, networkCallback)
        Log.d(javaClass.simpleName, "[${Thread.currentThread().name}] registerNetworkCallback AFTER")
    }
    Log.d(javaClass.simpleName, "[${Thread.currentThread().name}] return isAvailable BEFORE")
    return isAvailable
}

当我调用时,isNetworkAvailable(NetworkCapabilities.TRANSPORT_WIFI)输出如下:

[DefaultDispatcher-worker-1] registerNetworkCallback 之前
[DefaultDispatcher-worker-1] registerNetworkCallback 之后

但是,onAvailableandonLost永远不会被调用。

参考

有关的

4

1 回答 1

3

原来你想要做的相关 API 不是异步的,所以不需要协程:

private fun ConnectivityManager.isNetworkAvailable(
    vararg transportType: /* android.net.NetworkCapabilities.Transport */ Int)
: Boolean {
    val network = getActiveNetwork()
    val caps = getNetworkCapabilities(network)
    return caps != null && transportType.all(caps::hasTransport)
}

这只需要Manifest.permission.ACCESS_NETWORK_STATE.

如果您想主动搜索具有所需功能的网络,则需要使用requestNetworkAPI。(和许可Manifest.permission.CHANGE_NETWORK_STATE

于 2020-03-16T19:25:18.587 回答