从 Android 22 开始,如何同步检索某些传输类型的网络状态?
Posted
技术标签:
【中文标题】从 Android 22 开始,如何同步检索某些传输类型的网络状态?【英文标题】:How to synchronously retrieve network status for certain transport types as of 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
不过,onAvailable
和 onLost
永远不会被调用。
参考文献
这是受到codelabs/building-kotlin-extensions-library/#4 的启发。有关示例应用程序,请参阅FusedLocationProviderClient.awaitLastLocation()
。
相关
Using Firebase on Android with Kotlin Coroutines Callbacks and Kotlin Flows Cancellation in coroutines MovieHut/NetworkRepository.kt【问题讨论】:
您是否添加了使用互联网的权限 是的,<uses-permission android:name="android.permission.INTERNET" />
在 AndroidManifest.xml 中。
听说当天的协程builder函数是suspendCancellableCoroutine
@EpicPandaForce 你有没有错过我在sn-p代码中使用了这个函数?
是的。不知道除了你需要suspendCancellableCoroutine
之外,还有什么问题,哎呀。
【参考方案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 && transportType.all(caps::hasCapability)
,这是您切换WIFI时的情况。
这太棒了,很好的参考,但不幸的是,对于 23 岁以下,这需要添加一点条件以上是关于从 Android 22 开始,如何同步检索某些传输类型的网络状态?的主要内容,如果未能解决你的问题,请参考以下文章
如何在没有一年的情况下检索从 Google 通讯录同步的联系人事件?
如何将温度值(从服务)检索到 AppWidgetProvider