CybeX
CybeX

Reputation: 2406

Difference between registerDefaultNetworkCallback and registerNetworkCallback

I came across registerDefaultNetworkCallback and registerNetworkCallback while updating my Android app for API 28.

Having reviewed the documentation, I cannot find the difference between registering a network callback and registering a default network callback.

When will one use which?

Thanks in advance :)

Upvotes: 34

Views: 21344

Answers (7)

Zbarcea Christian
Zbarcea Christian

Reputation: 9548

Here's a solution which works for both Android versions (24 and above, and below):

class NetworkMonitor(
    private val application: Application,
    val onChange: (isConnected: Boolean) -> Unit
) {
    fun register() {
        (application.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).let { connectivityManager ->
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                registerAPI24AndAbove(connectivityManager)
            } else {
                registerAPI24Below(connectivityManager)
            }
        }
    }

    private fun registerAPI24AndAbove(connectivityManager: ConnectivityManager) {
        connectivityManager.registerDefaultNetworkCallback(buildNetworkCallback())
    }

    private fun registerAPI24Below(connectivityManager: ConnectivityManager) {
        NetworkRequest.Builder()
            .addCapability(NetworkCapabilities.TRANSPORT_CELLULAR)
            .addCapability(NetworkCapabilities.TRANSPORT_WIFI)
            .build().let { networkRequest ->
                connectivityManager.registerNetworkCallback(networkRequest, buildNetworkCallback())
            }
    }

    private fun buildNetworkCallback(): ConnectivityManager.NetworkCallback {
        return object : ConnectivityManager.NetworkCallback() {

            override fun onAvailable(network: Network) {
                [email protected](true)
            }

            override fun onLost(network: Network) {
                [email protected](false)
            }

        }
    }
}

Make sure you declare the required permission!

Manifest.permission.ACCESS_NETWORK_STATE

Then in your Application class:

class MyApp : Application() {

    override fun onCreate() {
        super.onCreate()

        NetworkMonitor(this) { isConnected ->
            if (isConnected) {
                // Do your thing
            } else {
                // Do your other thing
            }
        }.register()
    }

}

Upvotes: 0

VadzimV
VadzimV

Reputation: 1261

The most important difference was highlighted by always-learning. My answer will be the same, but I will try to explain it in a different way.

The device can be connected to a few networks simultaneously(WiFI and mobile for example). Android chooses one of the connected networks as the default so that default network is used for requests.

The difference is registerNetworkCallback notifies about all connected networks, and registerDefaultNetworkCallback notifies about default netowork.

This is why you can't pass filter in registerDefaultNetworkCallback - it doesn't make sense to filter one chosen default network, but it does make sense for registerNetworkCallback because there are can be many available networks.

You can find a very good example on Android Developer that explains which callbacks do you get in registerDefaultNetworkCallback and registerNetworkCallback

Upvotes: 7

Always Learning
Always Learning

Reputation: 2743

Most of these answers are more or less correct. That said, what I can add is that default network has a particular meaning in Android hence the difference in naming. The default network pertains to whichever network is chosen as the "best" device wide network. This network will be used by default for any connectivity requests.

If you are using a phone and only have a Cellular connection available, that will be the default network. As soon as you connect to Wi-Fi however that will become the default network as it is considered the "best" network and all connectivity requests which don't specify anything different will now use it by default whether they realize it or not. This is because Wi-Fi is considered better then Cellular as long as Wi-Fi has NetworkCapability.NET_CAPABILITY_NOT_METERED. Now if it turns out that the Wi-Fi network is in fact a metered network while cellular isn't, then the default network would switch back to cellular.

Therefore when you use registerDefaultNetworkCallback(), what you are really saying is let me know about changes that occur on the network tagged as the "best" network on the device that all apps will use by default unless they request something different. This is why you don't need to pass a NetworkCapability as part of the registration since the default network is controlled by the framework.

registerNetworkCallback() is similar except that it doesn't care about the default network. You give it some NetworkCapability and you track on any networks that satisfy those network capabilities regardless of whether they are the default or not.

You can see more by looking at getDefaultNetwork() in ConnectivityService.

Upvotes: 4

Yu Kakizaki
Yu Kakizaki

Reputation: 31

i found guide document page: Android Developers > Docs > Guides > Reading network state.

registerDefaultNetworkCallback , registerNetworkCallback and default network are explained.

Upvotes: 1

xjcl
xjcl

Reputation: 15329

registerNetworkCallback() was added in API level 21 (Android 5.0, Lollipop). It allows you to listen for changes in networks which satisfy a certain transport type (WiFi, cellular, Bluetooth, ...) and capability (SMS, NOT_METERED, ...).

registerDefaultNetworkCallback() was added in API level 24 (Android 7.0, Nougat) and uses your callback when any network change occurs, regardless of transport type and capability.


Example for registerNetworkCallback(). At least in my case I do not care about the filters and want my code to run for any network type. This can be achieved with an empty Builder object:

/* Automatically start a download once an internet connection is established */
val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
// could filter using .addCapability(int) or .addTransportType(int) on Builder
val networkChangeFilter = NetworkRequest.Builder().build()
cm.registerNetworkCallback(networkChangeFilter, 
    object : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network) = downloadStuff()
    }
)

Above code is equivalent to this code with registerDefaultNetworkCallback():

val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
cm.registerDefaultNetworkCallback(
    object : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network) = downloadStuff()
    }
)

The confusingly named NetworkRequest is actually just a filter for transport type and capability.


The Default version is less code, but has a lower API level and thus supports fewer phones (74% vs 94%). Since I could not find a backwards-compatible version of this API call in ConnectivityManagerCompat I recommend using the first version if API levels 21-23 matter to you.

Upvotes: 17

xarlymg89
xarlymg89

Reputation: 2617

As far as I've understood, and aside of the information provided by @MihaiV , there's another difference between them.

ConnectivityManager.registerDefaultNetworkCallback() was added in API 24 (or 26, depending if you use it along a Handler).

And ConnectivityManager.registerNetworkCallback() was added in API 21 (or API 23 if used along a NetworkRequest.

Upvotes: 1

MihaiV
MihaiV

Reputation: 705

As far as I understood, the difference between registerDefaultNetworkCallback and registerNetworkCallback it's only based on customisation.
registerDefaultNetworkCallback works (surprisingly) as a default network listener, while registerNetworkCallback it's more configurable. For example:

    val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

    val builder = NetworkRequest.Builder()
    builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)

    val networkRequest = builder.build()
    connectivityManager.registerNetworkCallback(networkRequest, 
    object : ConnectivityManager.NetworkCallback () {
        override fun onAvailable(network: Network?) {
            super.onAvailable(network)
            Log.i("Test", "Network Available")
        }

        override fun onLost(network: Network?) {
            super.onLost(network)
            Log.i("Test", "Connection lost")
        }
    })

Here onAvailable will be called only if the user connects to a cellular network (by connecting to WiFi it won't log anything). The same does onLost when disconnecting from cellular network.

If we do it like this:

    connectivityManager.registerDefaultNetworkCallback(object  : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network?) {
            super.onAvailable(network)
            Log.i("Test", "Default -> Network Available")
        }

        override fun onLost(network: Network?) {
            super.onLost(network)
            Log.i("Test", "Default -> Connection lost")
        }
    })

Both functions work as default callbacks when the user is connecting (or disconnecting) to/from a network (it can be either WiFi or cellular).

These are just some very basic examples. Of course NetworkRequest can have a lot of configurations by setting its capability or transportType. You can read more about these in the official documentation of NetworkRequest.

Upvotes: 38

Related Questions