How to synchronously retrieve network status for certain transport types as of Android 22?

JJD :

I changed the question title since Kiskae provided a solution to the broader problem which makes the question about wrapping a callback API needless for the particular problem. The former question title was:

How to wrap asynchronous callback into suspend function using Coroutines?


I am trying to wrap the ConnectivityManager.NetworkCallback API (>= SDK level 21) of the Android framework into a suspend function to facilitate a synchronous 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
}

When I call the isNetworkAvailable(NetworkCapabilities.TRANSPORT_WIFI) then the following is output:

[DefaultDispatcher-worker-1] registerNetworkCallback BEFORE
[DefaultDispatcher-worker-1] registerNetworkCallback AFTER

The onAvailable and onLost are never called, though.

References

Related

Kiskae :

Turns out the relevant API for what you want to do isn't async, so coroutines should not be required:

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)
}

This only requires Manifest.permission.ACCESS_NETWORK_STATE.

If you want to actively search for a network that has the capabilities required, you will need to use the requestNetwork API. (and permission Manifest.permission.CHANGE_NETWORK_STATE)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=345919&siteId=1