ConnectivityManager.CONNECTIVITY_ACTION deprecated

Android

Android Problem Overview


In Android N, it is mentioned on the official website that "Apps targeting Android N do not receive CONNECTIVITY_ACTION broadcasts". And it is also mentioned that JobScheduler can be used as an alternative. But the JobScheduler doesn't provide exactly the same behavior as CONNECTIVITY_ACTION broadcast.

In my Android application, I was using this broadcast to know the network state of the device. I wanted to know if this state was CONNECTING or CONNECTED with the help of CONNECTIVITY_ACTION broadcast and it was best suited for my requirement.

Now that it is deprecated, can any one suggest me the alternative approach to get current network state?

Android Solutions


Solution 1 - Android

What will be deprecated is the ability for a backgrounded application to receive network connection state changes.

As David Wasser said you can still get notified of connectivity changes if the app component is instantiated (not destroyed) and you have registered your receiver programmatically with its context, instead of doing it in the manifest.

Or you can use NetworkCallback instead. In particular, you will need to override onAvailable for connected state changes.

Let me draft a snippet quickly:

public class ConnectionStateMonitor extends NetworkCallback {
   
   final NetworkRequest networkRequest;
   
   public ConnectionStateMonitor() {
       networkRequest = new NetworkRequest.Builder()
           .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
           .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
           .build();
   }

   public void enable(Context context) {
       ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
       connectivityManager.registerNetworkCallback(networkRequest, this);
   }

   // Likewise, you can have a disable method that simply calls ConnectivityManager.unregisterNetworkCallback(NetworkCallback) too.

   @Override
   public void onAvailable(Network network) {
       // Do what you need to do here
   }
}

Solution 2 - Android

I will update Sayem's answer for fix lint issues its showing to me.

class ConnectionLiveData(val context: Context) : LiveData<Boolean>() {

    private var connectivityManager: ConnectivityManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager

    private lateinit var connectivityManagerCallback: ConnectivityManager.NetworkCallback

    private val networkRequestBuilder: NetworkRequest.Builder = NetworkRequest.Builder()
        .addTransportType(android.net.NetworkCapabilities.TRANSPORT_CELLULAR)
        .addTransportType(android.net.NetworkCapabilities.TRANSPORT_WIFI)

    override fun onActive() {
        super.onActive()
        updateConnection()
        when {
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> connectivityManager.registerDefaultNetworkCallback(getConnectivityMarshmallowManagerCallback())
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> marshmallowNetworkAvailableRequest()
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> lollipopNetworkAvailableRequest()
            else -> {
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                    context.registerReceiver(networkReceiver, IntentFilter("android.net.conn.CONNECTIVITY_CHANGE")) // android.net.ConnectivityManager.CONNECTIVITY_ACTION
                }
            }
        }
    }

    override fun onInactive() {
        super.onInactive()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            connectivityManager.unregisterNetworkCallback(connectivityManagerCallback)
        } else {
            context.unregisterReceiver(networkReceiver)
        }
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private fun lollipopNetworkAvailableRequest() {
        connectivityManager.registerNetworkCallback(networkRequestBuilder.build(), getConnectivityLollipopManagerCallback())
    }

    @TargetApi(Build.VERSION_CODES.M)
    private fun marshmallowNetworkAvailableRequest() {
    connectivityManager.registerNetworkCallback(networkRequestBuilder.build(), getConnectivityMarshmallowManagerCallback())
    }

    private fun getConnectivityLollipopManagerCallback(): ConnectivityManager.NetworkCallback {
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
           connectivityManagerCallback = object : ConnectivityManager.NetworkCallback() {
               override fun onAvailable(network: Network?) {
                   postValue(true)
               }

               override fun onLost(network: Network?) {
                   postValue(false)
               }
           }
           return connectivityManagerCallback
       } else {
           throw IllegalAccessError("Accessing wrong API version")
       }
    }

    private fun getConnectivityMarshmallowManagerCallback(): ConnectivityManager.NetworkCallback {
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
          connectivityManagerCallback = object : ConnectivityManager.NetworkCallback() {
            override fun onCapabilitiesChanged(network: Network?, networkCapabilities: NetworkCapabilities?) {
                networkCapabilities?.let { capabilities ->
                    if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
                        postValue(true)
                    }
                }
            }
            override fun onLost(network: Network?) {
                postValue(false)
            }
         }
         return connectivityManagerCallback
       } else {
         throw IllegalAccessError("Accessing wrong API version")
       }
    }

    private val networkReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            updateConnection()
        }
    }

    private fun updateConnection() {
        val activeNetwork: NetworkInfo? = connectivityManager.activeNetworkInfo
        postValue(activeNetwork?.isConnected == true)
    }
}

And same usage:

    val connectionLiveData = ConnectionLiveData(context)
    connectionLiveData.observe(this, Observer { isConnected ->
           isConnected?.let {
             // do job
           }
    })

Btw thanks sayem for your solution.

Solution 3 - Android

The documentation for Android N states:

> Apps targeting Android N do not receive CONNECTIVITY_ACTION > broadcasts, even if they have manifest entries to request notification > of these events. Apps running in the foreground can still listen for > CONNECTIVITY_CHANGE on their main thread if they request notification > with a BroadcastReceiver.

This means that you can still register a BroadcastReceiver if your app is running in the foreground, in order to detect changes in the network connectivity.

Solution 4 - Android

Please check first @Amokrane Chentir answer for android N support.

For those who wants to support in all api level & observe it in ui, please check bellow code.

LiveData of NetworkConnection:

class ConnectionLiveData(val context: Context) : LiveData<Boolean>(){

    var  intentFilter = IntentFilter(CONNECTIVITY_ACTION)
    private var  connectivityManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
    private lateinit var networkCallback : NetworkCallback

    init {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            networkCallback = NetworkCallback(this)
        }
    }

    override fun onActive() {
        super.onActive()
        updateConnection()
        when {
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> connectivityManager.registerDefaultNetworkCallback(networkCallback)
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> {
                val builder = NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).addTransportType(TRANSPORT_WIFI)
                connectivityManager.registerNetworkCallback(builder.build(), networkCallback)
            }
            else -> {
                context.registerReceiver(networkReceiver, intentFilter)
            }
        }
    }

    override fun onInactive() {
        super.onInactive()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            connectivityManager.unregisterNetworkCallback(networkCallback)
        } else{
            context.unregisterReceiver(networkReceiver)
        }
    }


    private val networkReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            updateConnection()
        }
    }

    fun updateConnection() {
        val activeNetwork: NetworkInfo? = connectivityManager.activeNetworkInfo
        postValue(activeNetwork?.isConnectedOrConnecting == true)
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    class NetworkCallback(val liveData : ConnectionLiveData) : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network?) {
            liveData.postValue(true)
        }

        override fun onLost(network: Network?) {
            liveData.postValue(false)
        }
    }
}

observe in UI (Activity/Fragment):

val connectionLiveData = ConnectionLiveData(context)
    connectionLiveData.observe(this, Observer { 
       // do whatever you want with network connectivity change 
})

Solution 5 - Android

Based on @KebabKrabby's answer:

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Context.CONNECTIVITY_SERVICE
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.ConnectivityManager.CONNECTIVITY_ACTION
import android.net.ConnectivityManager.EXTRA_NO_CONNECTIVITY
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
import android.os.Build
import androidx.lifecycle.LiveData

class ConnectivityWatcher(
    private val context: Context
): LiveData<Boolean>() {

    private lateinit var networkCallback: ConnectivityManager.NetworkCallback
    private lateinit var broadcastReceiver: BroadcastReceiver

    override fun onActive() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
            networkCallback = createNetworkCallback()
            cm.registerDefaultNetworkCallback(networkCallback)
        } else {
            val intentFilter = IntentFilter(CONNECTIVITY_ACTION)
            broadcastReceiver = createBroadcastReceiver()
            context.registerReceiver(broadcastReceiver, intentFilter)
        }
    }

    override fun onInactive() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
            cm.unregisterNetworkCallback(networkCallback)
        } else {
            context.unregisterReceiver(broadcastReceiver)
        }
    }

    private fun createNetworkCallback() = object : ConnectivityManager.NetworkCallback() {

        override fun onCapabilitiesChanged(
            network: Network,
            networkCapabilities: NetworkCapabilities
        ) {
            val isInternet = networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)
            val isValidated = networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)
            postValue(isInternet && isValidated)
        }

        override fun onLost(network: Network) {
            postValue(false)
        }
    }

    private fun createBroadcastReceiver() = object : BroadcastReceiver() {

        override fun onReceive(context: Context?, intent: Intent?) {
            val isNoConnectivity = intent?.extras?.getBoolean(EXTRA_NO_CONNECTIVITY) ?: true
            postValue(!isNoConnectivity)
        }
    }
}

And using of it almost the same as in the original answer (if observe from an Activity, for example):

ConnectivityWatcher(this).observe(this, Observer {
    Log.i("*-*-*", "is internet available? - ${if (it) "Yes" else "No"}")
})

Solution 6 - Android

I ran into the same problem few days back and I decided to use this library Android-Job

This library uses JobSchedular, GcmNetworkManager and BroadcastReceiver depending on which Android version the app is running on.

Starting a job is fairly easy

new JobRequest.Builder(DemoSyncJob.TAG)
            .setRequiresCharging(true)
            .setRequiresDeviceIdle(false)
            .setRequiredNetworkType(JobRequest.NetworkType.CONNECTED) // this is what gets the job done
            .build()
            .schedule();

Solution 7 - Android

I wrote a Kotlin implementation which is based on Sayam's answer but without LiveData. I decided to invoke the (at this point in time) latest API method (ConnectivityManager#registerDefaultNetworkCallback) which targets Android Nougat.

/**
 * Observes network connectivity by consulting the [ConnectivityManager].
 * Observing can run infinitely or automatically be stopped after the first response is received.
 */
class ConnectivityObserver @JvmOverloads constructor(

        val context: Context,
        val onConnectionAvailable: () -> Unit,
        val onConnectionLost: () -> Unit = {},
        val shouldStopAfterFirstResponse: Boolean = false

) {

    private val connectivityManager
        get() = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

    @Suppress("DEPRECATION")
    private val intentFilter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)

    private val broadCastReceiver = object : BroadcastReceiver() {

        @Suppress("DEPRECATION")
        override fun onReceive(context: Context?, intent: Intent?) {
            if (ConnectivityManager.CONNECTIVITY_ACTION != intent?.action) {
                return
            }
            val networkInfo = connectivityManager.activeNetworkInfo
            if (networkInfo != null && networkInfo.isConnectedOrConnecting) {
                onConnectionAvailable.invoke()
            } else {
                onConnectionLost.invoke()
            }
            if (shouldStopAfterFirstResponse) {
                stop()
            }
        }

    }

    private lateinit var networkCallback: ConnectivityManager.NetworkCallback

    init {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            networkCallback = object : ConnectivityManager.NetworkCallback() {

                override fun onAvailable(network: Network) {
                    super.onAvailable(network)
                    onConnectionAvailable.invoke()
                    if (shouldStopAfterFirstResponse) {
                        stop()
                    }
                }

                override fun onLost(network: Network?) {
                    super.onLost(network)
                    onConnectionLost.invoke()
                    if (shouldStopAfterFirstResponse) {
                        stop()
                    }
                }
            }
        }
    }

    fun start() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            // Decouple from component lifecycle, use application context.
            // See: https://developer.android.com/reference/android/content/Context.html#getApplicationContext()
            context.applicationContext.registerReceiver(broadCastReceiver, intentFilter)
        } else {
            connectivityManager.registerDefaultNetworkCallback(networkCallback)
        }
    }

    fun stop() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            context.applicationContext.unregisterReceiver(broadCastReceiver)
        } else {
            connectivityManager.unregisterNetworkCallback(networkCallback)
        }
    }

}

Usage:

val onConnectionAvailable = TODO()
val connectivityObserver = ConnectivityObserver(context, onConnectionAvailable)
connectivityObserver.start()
connectivityObserver.stop()

or:

val onConnectionAvailable = TODO()
val onConnectionLost = TODO()
ConnectivityObserver(context, 
    onConnectionAvailable, 
    onConnectionLost, 
    shouldStopAfterFirstResponse = true
).start()

Don't forget to add the ACCESS_NETWORK_STATE permission in your AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

I am looking forward to reading helpful comments and improvements from you.

Solution 8 - Android

Apps targeting Android N (Nougat) do not receive CONNECTIVITY_ACTION broadcasts defined in the manifest (see Svelte).

Possible Solutions:

See also https://stackoverflow.com/questions/46163131/android-o-detect-connectivity-change-in-background

Solution 9 - Android

I agree with the answer suggested by @rds.

Do keep in mind that CONNECTIVITY_ACTION is deprecated in API level 28.

> If you have the requirement that Wifi state (connect/disconnect) should be detected despite > app being killed and you want to target the latest version then you > don't have much choice.

You need to use connectivityManager.registerNetworkCallback(networkRequest, networkCallback)

Question is that you can't use BroadcastReceiver so how then?

You can either use JobScheduler or better if WorkManager (Periodic Request). Why Periodic because if it is a OneTimeRequest then it will only be able to run once and keep listening while your app is in foreground.

Documentation says:

> The callbacks will continue to be called until either the application exits or link #unregisterNetworkCallback(NetworkCallback)} is called.

Once app is killed or removed from recent apps list, networkCallback won't be able to listen.

So, you need such periodic jobs to make the app continuously listen. How much should be the duration? That's up to you and depends on case to case.

I know it is a bit ugly way but this is how it is. One challenge could be that if the user's device is in Doze mode or app is in Standby State, your job might be delayed.

Solution 10 - Android

When we register a network callback using the registerNetworkCallback method sometimes it does not trigger and sometimes it does trigger false-positive:

  1. If we start an app with internet connection the onAvailable method triggers.
  2. But if there is no internet connection on device when we start an app nothing of the NetworkCallback is called (it's very strange because of p. 1)
  3. If we have wifi connection but without internet connection onAvailable method triggers. And I think it's false-positive behavior because we expect internet connection observing.

As you see in below code by default internet connection is available and it triggers only if it changes. No false-positive triggers.

Just summarize this and this answers (but only for API >= 21):

class ConnectionManager @Inject constructor(
    private val connectivityManager: ConnectivityManager,
    private val disposable: CompositeDisposable,
    private val singleTransformer: SingleTransformer<*, *>
) : LiveData<Boolean>() {

    private var isNetworkAvailable = true

    private val builder = NetworkRequest.Builder()
        .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
        .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)

    private val callback = object : ConnectivityManager.NetworkCallback() {

        override fun onAvailable(network: Network) {
            ping()
        }

        override fun onLost(network: Network) {
            ping()
        }
    }

    private fun ping() {
        disposable.add(
            Single.fromCallable {
                try {
                    val timeoutMs = 1500
                    val socket = Socket()
                    val socketAddress = InetSocketAddress("8.8.8.8", 53)

                    socket.connect(socketAddress, timeoutMs)
                    socket.close()
                    true
                } catch (e: IOException) {
                    false
                }
            }
                .compose(singleTransformer as SingleTransformer<Boolean, Boolean>)
                .subscribeBy {
                    if (isNetworkAvailable != it){
                        value = it
                        isNetworkAvailable = it
                    }
                }
        )
    }

    override fun onActive() {
        ping()
        connectivityManager.registerNetworkCallback(builder.build(), callback)
    }

    override fun onInactive() {
        disposable.clear()
        connectivityManager.unregisterNetworkCallback(callback)
    }
}

How to provide the dependencies

@Provides
fun provideTransformer(): SingleTransformer<Boolean, Boolean> {
    return SingleTransformer<Boolean, Boolean> { upstream: Single<Boolean> ->
        upstream.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
    }
}

@Singleton
@Provides
fun provideConnectivityManager(context: Context): ConnectivityManager =
        context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

@Singleton
@Provides
fun provideConnectionManager(connectivityManager: ConnectivityManager, singleTransformer: SingleTransformer<Boolean, Boolean>): ConnectionManager =
        ConnectionManager(connectivityManager, singleTransformer)

And how to use:

@Inject
lateinit var connectionManager: ConnectionManager

//....

viewLifecycleOwner.observe(connectionManager) { isInternetAvailable ->
    // TODO 
}

Solution 11 - Android

I've decided to check on the solution here, and made some improvements and sample:

ConnectionLiveData.kt

class ConnectionLiveData(private val context: Context) : LiveData<Boolean>() {
    private val connectivityManager: ConnectivityManager = context.getSystemService()!!
    private lateinit var networkReceiver: BroadcastReceiver
    private lateinit var connectivityManagerCallback: ConnectivityManager.NetworkCallback

    @UiThread
    override fun setValue(value: Boolean?) {
        if (getValue() == value)
            return
        super.setValue(value)
    }

    @UiThread
    override fun onActive() {
        super.onActive()
        updateConnection()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            connectivityManagerCallback = object : ConnectivityManager.NetworkCallback() {
                @WorkerThread
                override fun onCapabilitiesChanged(network: Network,
                    networkCapabilities: NetworkCapabilities) {
                    super.onCapabilitiesChanged(network, networkCapabilities)
                    if (networkCapabilities.hasCapability(
                            NetworkCapabilities.NET_CAPABILITY_INTERNET)
                        && networkCapabilities.hasCapability(
                            NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
                        postValue(true)
                    }
                }

                @WorkerThread
                override fun onLost(network: Network) {
                    postValue(false)
                }
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                connectivityManager.registerDefaultNetworkCallback(connectivityManagerCallback)
            } else {
                val networkRequest = NetworkRequest.Builder()
                    .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build()
                connectivityManager.registerNetworkCallback(networkRequest,
                    connectivityManagerCallback)
            }
        } else {
            networkReceiver = object : BroadcastReceiver() {
                @UiThread
                override fun onReceive(context: Context, intent: Intent) {
                    updateConnection()
                }
            }
            @Suppress("DEPRECATION")
            context.registerReceiver(networkReceiver,
                IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
        }
    }

    @UiThread
    override fun onInactive() {
        super.onInactive()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
            connectivityManager.unregisterNetworkCallback(connectivityManagerCallback)
        else
            context.unregisterReceiver(networkReceiver)
    }

    @UiThread
    @Suppress("DEPRECATION")
    private fun updateConnection() {
        val activeNetwork: NetworkInfo? = connectivityManager.activeNetworkInfo
        value = activeNetwork?.isConnected == true
    }
}

MainActivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val textView = findViewById<TextView>(R.id.textView)
        ConnectionLiveData(this).observe(this, {
            textView.text = if (it) "connected" else "disconnected"
            Log.d("AppLog", "connected?$it")
        })
        val internetSettings = findViewById<View>(R.id.internetSettings)
        internetSettings.isVisible = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
        internetSettings.setOnClickListener {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
                startActivity(Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY))
        }
        findViewById<View>(R.id.wifiSettings).setOnClickListener {
            startActivity(Intent(Settings.ACTION_WIFI_SETTINGS))
        }
        findViewById<View>(R.id.mobileDataSettings).setOnClickListener {
            startActivity(Intent(Settings.ACTION_DATA_ROAMING_SETTINGS))
        }
    }
}

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center"
    android:orientation="vertical" tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" />

    <Button
        android:id="@+id/internetSettings" android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="internet settings" />

    <Button
        android:id="@+id/wifiSettings" android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="wifi settings" />

    <Button
        android:id="@+id/mobileDataSettings" android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="mobile-data settings" />
</LinearLayout>

manifest requires:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Solution 12 - Android

Here is my solution in Java! from android LOLLIPOP to android S and above

@RequiresApi (api = Build.VERSION_CODES.LOLLIPOP)
public final class NetworkWatcher extends LiveData<Boolean> {
//    Variables
private final Context context;

private final ConnectivityManager connectivityManager;
private ConnectivityManager.NetworkCallback networkCallback;

private NetworkRequest networkRequest;

private NetworkWatcher.NetworkStateWatcherReceiver networkStateWatcherReceiver;


//    Constructors
public NetworkWatcher(@NonNull Context context){
    this.context = context;

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
        this.connectivityManager = context.getSystemService(ConnectivityManager.class);

        this.networkCallback = new ConnectivityManager.NetworkCallback(){
            @Override
            public void onLost(@NonNull Network network) {
                NetworkWatcher.super.postValue(false);
            }

            @Override
            public void onCapabilitiesChanged(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
                NetworkWatcher.super.postValue(
                        networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
                                networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
                );
            }
        };
        this.networkRequest = new NetworkRequest.Builder()
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                .addTransportType(NetworkCapabilities.TRANSPORT_VPN)
                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
                .build();
    } else {
        this.networkStateWatcherReceiver = new NetworkStateWatcherReceiver();
        this.networkStateWatcherReceiver.setOnNetworkChangedListener(NetworkWatcher.super::postValue);
    }
}


//    Override methods
@Override
protected void onActive() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
            this.connectivityManager.registerBestMatchingNetworkCallback(this.networkRequest, this.networkCallback, null);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
            this.connectivityManager.registerDefaultNetworkCallback(this.networkCallback);
        } else {
            this.connectivityManager.registerNetworkCallback(this.networkRequest, this.networkCallback);
        }
    } else {
        this.context.registerReceiver(
                this.networkStateWatcherReceiver,
                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
        );
    }
}

@Override
protected void onInactive() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
        this.connectivityManager.unregisterNetworkCallback(this.networkCallback);
    } else {
        this.context.unregisterReceiver(this.networkStateWatcherReceiver);
    }
}



//    Inner method classes
@TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
private static final class NetworkStateWatcherReceiver extends BroadcastReceiver {
    //        Variables
    private NetworkStateWatcherReceiver.OnNetworkChangedListener onNetworkChangedListener;


    //        Constructors
    public NetworkStateWatcherReceiver() {
    }


    //        Override methods
@Override
    public void onReceive(@NonNull Context context, @NonNull Intent intent) {
        if (this.onNetworkChangedListener != null) {
            boolean isConnected = this.isConnected(context);
            this.onNetworkChangedListener.onNetworkChangedListener(isConnected);
        }
    }


    //        Methods
    private boolean isConnected(@NonNull Context context){
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();

        return networkInfo != null && networkInfo.isConnected();
    }
    public void setOnNetworkChangedListener(@Nullable OnNetworkChangedListener onNetworkChangedListener) {
        this.onNetworkChangedListener = onNetworkChangedListener;
    }



    //        Inner interfaces
private interface OnNetworkChangedListener{
        void onNetworkChangedListener(boolean isConnected);
    }
}
}

Use it in your main activity inside onCreate method

new NetworkWatcher(this).observe(this, aBoolean -> {
        if (aBoolean){
            // Internet connection available
        } else {
           // No internet connection
        }
    });

Solution 13 - Android

You can easily use the library com.github.vladan29:internet_checker:1.0.3. With that library no need to know reactive programming and think about removing observers. Only a few lines of code will provide continuous and safe checking of internet connection.

You can find all necessary instructions at the: https://github.com/vladan29/internet_checker/blob/master/README.md#internet_checker

Solution 14 - Android

Nothing fancy in this I just converted the above answer to java as there are no answers with java.

  public class ConnectivityWatcher extends LiveData<Boolean> {
    private static final String TAG = "ConnectivityWatcher";
    private final ConnectivityManager connectivityManager;
    private ConnectivityManager.NetworkCallback connectivityManagerCallback;
    private final NetworkRequest.Builder networkRequestBuilder;
    @NotNull
    private final Context context;

    protected void onActive() {
        super.onActive();
        this.updateConnection();
        if (Build.VERSION.SDK_INT >= 24) {
            try {
                this.connectivityManager.registerDefaultNetworkCallback(this.getConnectivityMarshmallowManagerCallback());
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } else if (Build.VERSION.SDK_INT >= 23) {
            try {
                this.marshmallowNetworkAvailableRequest();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } else if (Build.VERSION.SDK_INT >= 21) {
            try {
                this.lollipopNetworkAvailableRequest();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

    }

    protected void onInactive() {
        super.onInactive();
        Log.e(TAG, "onInactive: I am inActive ");
        if (Build.VERSION.SDK_INT >= 21) {
            connectivityManager.unregisterNetworkCallback(connectivityManagerCallback);
        }

    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void lollipopNetworkAvailableRequest() throws IllegalAccessException {
        this.connectivityManager.registerNetworkCallback(this.networkRequestBuilder.build(), this.getConnectivityLollipopManagerCallback());
    }

    @TargetApi(Build.VERSION_CODES.M)
    private void marshmallowNetworkAvailableRequest() throws IllegalAccessException {
        this.connectivityManager.registerNetworkCallback(this.networkRequestBuilder.build(), this.getConnectivityMarshmallowManagerCallback());
    }

    private ConnectivityManager.NetworkCallback getConnectivityLollipopManagerCallback() throws IllegalAccessException {
        if (Build.VERSION.SDK_INT >= 21) {
            this.connectivityManagerCallback = new ConnectivityManager.NetworkCallback() {
                public void onAvailable(@NotNull Network network) {
                    postValue(true);
                }

                public void onLost(@NotNull Network network) {
                    postValue(false);
                }
            };

            return this.connectivityManagerCallback;
        } else {
            throw new IllegalAccessException();
        }
    }

    private ConnectivityManager.NetworkCallback getConnectivityMarshmallowManagerCallback() throws IllegalAccessException {
        if (Build.VERSION.SDK_INT >= 23) {
            this.connectivityManagerCallback = new ConnectivityManager.NetworkCallback() {
                public void onCapabilitiesChanged(@NotNull Network network, @NotNull NetworkCapabilities networkCapabilities) {
                    if (connectivityManager != null) {
                        NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.getActiveNetwork());
                        if (capabilities != null) {
                            if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
                                postValue(true);
                            }
                        }
                    }
                }

                public void onLost(@NotNull Network network) {
                    postValue(false);
                }
            };

            return this.connectivityManagerCallback;
        } else {
            throw new IllegalAccessException();
        }
    }

    private void updateConnection() {
        boolean isConnected;
        NetworkInfo activeNetwork = this.connectivityManager.getActiveNetworkInfo();
        if (activeNetwork != null) {
            isConnected = activeNetwork.isConnected();
        } else {
            isConnected = false;
        }
        this.postValue(isConnected);
    }

    @NotNull
    public final Context getContext() {
        return this.context;
    }

    public ConnectivityWatcher(@NotNull Context context) {
        this.context = context;
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (cm == null) {
            throw new NullPointerException("null cannot be cast to non-null type android.net.ConnectivityManager");
        } else {
            this.connectivityManager = cm;
            this.networkRequestBuilder = (new NetworkRequest.Builder()).addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).addTransportType(NetworkCapabilities.TRANSPORT_WIFI).addTransportType(NetworkCapabilities.TRANSPORT_VPN);
        }
    }
}

Solution 15 - Android

While overriding onAvailable(Network network) does work sometimes, when onAvailable() is called, the new network might not be fully functional yet. I ended up using the following as per this doc https://developer.android.com/reference/android/net/ConnectivityManager.OnNetworkActiveListener

connectivityManager.addDefaultNetworkActiveListener()

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRaghuram dbView Question on Stackoverflow
Solution 1 - AndroidAmokrane ChentirView Answer on Stackoverflow
Solution 2 - AndroidKebab KrabbyView Answer on Stackoverflow
Solution 3 - AndroidDavid WasserView Answer on Stackoverflow
Solution 4 - AndroidSayemView Answer on Stackoverflow
Solution 5 - AndroidDmitryKanunnikoffView Answer on Stackoverflow
Solution 6 - AndroidNoman RafiqueView Answer on Stackoverflow
Solution 7 - AndroidJJDView Answer on Stackoverflow
Solution 8 - AndroidrdsView Answer on Stackoverflow
Solution 9 - AndroidWahib Ul HaqView Answer on Stackoverflow
Solution 10 - AndroidbitvaleView Answer on Stackoverflow
Solution 11 - Androidandroid developerView Answer on Stackoverflow
Solution 12 - Androiduser16828276View Answer on Stackoverflow
Solution 13 - AndroidVladan StarcevicView Answer on Stackoverflow
Solution 14 - AndroiddeveloperView Answer on Stackoverflow
Solution 15 - AndroidTony TamView Answer on Stackoverflow