【问题标题】:How to synchronously retrieve network status for certain transport types as of Android 22?从 Android 22 开始,如何同步检索某些传输类型的网络状态?
【发布时间】:2020-06-27 16:51:32
【问题描述】:

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

如何使用 Coroutines 将异步回调封装到挂起函数中?


我正在尝试将 Android 框架的 ConnectivityManager.NetworkCallback 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 BEFORE
[DefaultDispatcher-worker-1] registerNetworkCallback AFTER

不过,onAvailableonLost 永远不会被调用。

参考文献

相关

【问题讨论】:

  • 您是否添加了使用互联网的权限
  • 是的,&lt;uses-permission android:name="android.permission.INTERNET" /&gt;AndroidManifest.xml 中。
  • 听说当天的协程builder函数是suspendCancellableCoroutine
  • @EpicPandaForce 你有没有错过我在sn-p代码中使用了这个函数?
  • 是的。不知道除了你需要suspendCancellableCoroutine 之外,还有什么问题,哎呀。

标签: android kotlin kotlin-coroutines suspend android-connectivitymanager


【解决方案1】:

原来你想做的相关 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

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

【讨论】:

  • 感谢您发现此 API。 - 备注:您需要调用hasTransport 而不是hasCapability。 - 虽然getActiveNetwork API 仅在 SDK 级别 23 中可用,但我可以将其与已弃用的 getNetworkInfo 结合使用。
  • 您还需要检查caps == null,如return caps != null &amp;&amp; transportType.all(caps::hasCapability),这是您切换WIFI时的情况。
  • 这太棒了,很好的参考,但不幸的是,对于 23 岁以下,这需要添加一点条件
猜你喜欢
  • 1970-01-01
  • 2017-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-12
相关资源
最近更新 更多