androidandroid-connectivitymanager

Networkcallback called multiple times even after unregistering


In my android-app I need to call an API via my Wi-Fi connection which doesn't have an internet connection, even though cellular data is enabled. I manage to handle this with underneath code:

NetworkRequest.Builder builder;
builder = new NetworkRequest.Builder();
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
final ConnectivityManager connectivityManager = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
connectivityManager.requestNetwork(builder.build(), new ConnectivityManager.NetworkCallback() {
       @Override
       public void onAvailable(Network network) {
             connectivityManager.unregisterNetworkCallback(this);

             SendAPIRequest();
       }
});

So far so good. However, on certain android devices, the onAvailable method (and thus the SendAPIRequest method) is sometimes called multiple times, not always. As stated on developer.android.com, the networkcallback may be called more than once if the Network that is satisfying the request changes. (https://developer.android.com/reference/android/net/ConnectivityManager.NetworkCallback.html#onAvailable(android.net.Network)) But as you can see in my code, I unregister the networkcallback immediately to prevent this callback from being called another time, even if the Network changes. What am I doing wrong?


Solution

  • I know this is an old question, but for those who would be interested in this, I recently came across to notice that the callbacks are called from a worker thread. So there could be a race condition if you don't run your code on the main thread. Also onAvailable can still be called after unregistering the callback. So you will need to implement in a way that stuff you do inside of onAvailable is safe to be called even after its living context is gone.

    e.g. Proves onAvailable runs on a worker thread

    override fun onAvailable(network: Network) {
                        Logging.i(Logging.APP_STATE, "Network available")
                        if (Thread.currentThread() != Looper.getMainLooper().thread) {
                            throw RuntimeException("What? This doesn't run on the main thread!")
                        }
                        isConnected = true
                    }