从 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

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

参考文献

这是受到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

【问题讨论】:

您是否添加了使用互联网的权限 是的,&lt;uses-permission android:name="android.permission.INTERNET" /&gt;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 &amp;&amp; transportType.all(caps::hasCapability),这是您切换WIFI时的情况。 这太棒了,很好的参考,但不幸的是,对于 23 岁以下,这需要添加一点条件

以上是关于从 Android 22 开始,如何同步检索某些传输类型的网络状态?的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有一年的情况下检索从 Google 通讯录同步的联系人事件?

如何从自定义帐户中检索联系方式?

如何将温度值(从服务)检索到 AppWidgetProvider

如何使用 amplify 将 GraphQL 更改从 Appsync 同步到 Android?

如何将参数从 Flutter 传递给 Kotlin?

如何从 Android 应用程序与服务器同步倒数计时器