ConnectivityManager.CONNECTIVITY_ACTION deprecated
AndroidAndroid 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:
- Explicitly register a network callback with
ConnectivityManager.registernetworkCallback()
once the application is running. - Use a
JobScheduler
, and specify an unmetered network viasetRequiredNetworkType()
.
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:
- If we start an app with internet connection the
onAvailable
method triggers. - 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) - 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()