自 Android 22 起,如何同步检索某些传输类型的网络状态?
How to synchronously retrieve network status for certain transport types as of Android 22?
我更改了问题标题,因为 解决了更广泛的问题,这使得关于包装回调的问题 API 对于特定问题来说是不必要的。原题为:
How to wrap asynchronous callback into suspend function using 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
不过,onAvailable
和 onLost
从未被调用。
参考资料
- 这是受示例应用程序 codelabs/building-kotlin-extensions-library/#4. See
FusedLocationProviderClient.awaitLastLocation()
的启发。
相关
原来你想做的事情的相关 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
)
我更改了问题标题,因为
How to wrap asynchronous callback into suspend function using 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
不过,onAvailable
和 onLost
从未被调用。
参考资料
- 这是受示例应用程序 codelabs/building-kotlin-extensions-library/#4. See
FusedLocationProviderClient.awaitLastLocation()
的启发。
相关
原来你想做的事情的相关 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
)