Skip to content

Instantly share code, notes, and snippets.

@Abhinav1217
Last active November 11, 2022 05:02
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save Abhinav1217/0ff6b39e70fa38379d61e85e09b49fe7 to your computer and use it in GitHub Desktop.
Save Abhinav1217/0ff6b39e70fa38379d61e85e09b49fe7 to your computer and use it in GitHub Desktop.
Network Test on API 29 - Java
package com.example.simplenetwork;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.util.Log;
import androidx.annotation.NonNull;
public class CheckNetwork {
private Context context;
public CheckNetwork(Context context) {
this.context = context;
}
void registerDefaultNetworkCallback(){
try {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
assert connectivityManager != null;
connectivityManager.registerDefaultNetworkCallback(new ConnectivityManager.NetworkCallback(){
@Override
public void onAvailable(@NonNull android.net.Network network) {
super.onAvailable(network);
GlobalVars.isNetworkConnected = true;
Log.d("FLABS:", "onAvailable");
}
@Override
public void onLost(@NonNull android.net.Network network) {
super.onLost(network);
GlobalVars.isNetworkConnected = false;
Log.d("FLABS:", "onLost");
}
@Override
public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) {
super.onBlockedStatusChanged(network, blocked);
Log.d("FLABS:", "onBlockedStatusChanged");
}
@Override
public void onCapabilitiesChanged(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities);
Log.d("FLABS:", "onCapabilitiesChanged");
}
@Override
public void onLinkPropertiesChanged(@NonNull Network network, @NonNull LinkProperties linkProperties) {
super.onLinkPropertiesChanged(network, linkProperties);
Log.d("FLABS:", "onLinkPropertiesChanged");
}
@Override
public void onLosing(@NonNull Network network, int maxMsToLive) {
super.onLosing(network, maxMsToLive);
Log.d("FLABS:", "onLosing");
}
@Override
public void onUnavailable() {
super.onUnavailable();
Log.d("FLABS:", "onUnavailable");
}
});
} catch (Exception e) {
Log.d("FLABS: Exception in registerDefaultNetworkCallback", "hello");
GlobalVars.isNetworkConnected = false;
}
}
void registerNetworkCallback(){
try {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder builder = new NetworkRequest.Builder();
assert connectivityManager != null;
connectivityManager.registerNetworkCallback(builder.build(), new ConnectivityManager.NetworkCallback(){
@Override
public void onAvailable(@NonNull android.net.Network network) {
super.onAvailable(network);
GlobalVars.isNetworkConnected = true;
Log.d("FLABS:", "onAvailable");
}
@Override
public void onLost(@NonNull android.net.Network network) {
super.onLost(network);
GlobalVars.isNetworkConnected = false;
Log.d("FLABS:", "onLost");
}
@Override
public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) {
super.onBlockedStatusChanged(network, blocked);
Log.d("FLABS:", "onBlockedStatusChanged");
}
@Override
public void onCapabilitiesChanged(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities);
Log.d("FLABS:", "onCapabilitiesChanged");
}
@Override
public void onLinkPropertiesChanged(@NonNull Network network, @NonNull LinkProperties linkProperties) {
super.onLinkPropertiesChanged(network, linkProperties);
Log.d("FLABS:", "onLinkPropertiesChanged");
}
@Override
public void onLosing(@NonNull Network network, int maxMsToLive) {
super.onLosing(network, maxMsToLive);
Log.d("FLABS:", "onLosing");
}
@Override
public void onUnavailable() {
super.onUnavailable();
Log.d("FLABS:", "onUnavailable");
}
});
} catch (Exception e) {
Log.d("FLABS: Exception in registerNetworkCallback", "hello");
GlobalVars.isNetworkConnected = false;
}
}
}
package com.example.simplenetwork;
public class GlobalVars {
public static int counter = 0;
public static boolean isNetworkConnected = false;
}
package com.example.simplenetwork;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Register NetworkCallback -- need to call this when activity starts
CheckNetwork network = new CheckNetwork(getApplicationContext());
/*
* registerNetworkCallback() is available from API-21 and above
* But it will show status of all available network. Hence you would
* to query onCapabilitiesChanged() to make sure your intended network is active or not.
*/
// network.registerNetworkCallback();
/*
* network.registerDefaultNetworkCallback() is available from API-24
* Unlike its counterpart, it will only register status of current active network
* Hence no need to check with onCapabilitiesChanged(). But downside is that it
* is available since API-24 while current recommendation (in 2019) is to maintain
* minimum support for API-23 Marshmallo.
*/
network.registerDefaultNetworkCallback();
final TextView text = findViewById(R.id.test_message);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@SuppressLint({"SetTextI18n", "DefaultLocale"})
@Override
public void onClick(View view) {
GlobalVars.counter++;
if (GlobalVars.isNetworkConnected) {
text.setText(String.format("Counter is %d, And network is Connected", GlobalVars.counter));
} else {
text.setText(String.format("Counter is %d, And network is Not Connected", GlobalVars.counter));
}
}
});
}
}
@Abhinav1217
Copy link
Author

Switch logcat to debug, Clean existing logs, and filter by FLABS to see stuff triggered by my code.

@Abhinav1217
Copy link
Author

https://gist.github.com/PasanBhanu/730a32a9eeb180ec2950c172d54bb06a for complete debug log and other discussion. He is also the original guy for this gist.

@kalirajp91
Copy link

Thank u abhinav... it was working

@shamshadpattani
Copy link

is it support Min sdk is 19

@Abhinav1217
Copy link
Author

Abhinav1217 commented Feb 23, 2020

@shamshadpattani
registerDefaultNetworkCallback() was added in API 24, registerNetworkCallback() was added in API 21. I am currently using try/catch in my network class to use registerDefaultNetworkCallback() for api24 and above, and fallback to older NetworkInfo method for anything below it.

@shamshadpattani
Copy link

thank u bro

@saiga006
Copy link

saiga006 commented Nov 25, 2020

Hi @Abhinav1217,

   `
     public static boolean isDeviceConnected = false;

     // network callback code lies here

     public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
        
        super.onCapabilitiesChanged(network, networkCapabilities);

        Log.d(TAG," capabilities for the default network is " + networkCapabilities.toString());
        Log.d(TAG," does it have validated network connection internet presence : "
                + networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                + " is it validated "
                + networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED));
        if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {

            if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
                && !isDeviceConnected) {
                isDeviceConnected = true;
            } else if (!networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
                    && isDeviceConnected) {
                // handles the scenario when the internet is blocked by ISP,
                // or when the dsl/fiber/cable line to the router is disconnected
                isDeviceConnected = false;
                Log.d(TAG, " Internet Connection is lost temporarily for network: " + network.toString());
            }
        }
    }

    public void onLost(NonNull Network network) {
        super.onLost(network);
        if (isDeviceConnected) {
            isDeviceConnected = false;
            Log.d(TAG, "Connection is lost for network: " + network.toString());
        }
    }

`

I have maintained a state variable, to check whether a device has valid internet connection (isDeviceConnected -- static global variable)
based on NetworkCapabilities.NET_CAPABILITY_VALIDATED (this will say whether a network has active internet connection).

I was successful in receiving the network callback events when wifi was off, toggled on, or if the wifi has internet or in no internet scenarios.

@ksanbormukhim
Copy link

How do i unregistered this callback?

@Abhinav1217
Copy link
Author

Abhinav1217 commented Feb 1, 2021

@ksanbormukhim

How do i unregistered this callback?

From android documentation
Registers to receive notifications about changes in the system default network. The callbacks will continue to be called until either the application exits or unregisterNetworkCallback(android.net.ConnectivityManager.NetworkCallback) is called.

There is a limit of 100 pending callbacks per app imposed by OS. Unless there is a leak in your code, it is almost impossible to reach that because most of the time Unregistration is automatically handled when Lifecycle ends. And also here you can see that we are using a static singleton to reuse object. But if you are really unsure what will your code do, you can unregisterNetworkCallback in your Activitiy onDestroy() . But I wont recommend that because that means that when next activity loads, you would register it again and destroy it again which is performance regression. Follow the clean architecture code principles.

Only place I have actually used unregister callback is quit menu within my app. But in reality, its just redundant because OS automatically handles it when app is closed. (See docs I linked).

The original gist from pranas has more detailed discussion on how to handle network.

@ksanbormukhim
Copy link

@Abhinav1217 thanks for the clarification

@cesarborrego
Copy link

I have a special scenario, onLost function does not work in api 31, android 12
I implemented registerDefaultNetworkCallback, but when wifi o cellular network is disconeted, the network call back doesn't call the onLost
Anyone has the similar issue?

@Abhinav1217
Copy link
Author

@cesarborrego

I have to check this. At my work, I am working with API-31 and didn't see this issue at my work.
It is working for other API+Android_Version combo?
Meanwhile check the original post, https://gist.github.com/PasanBhanu/730a32a9eeb180ec2950c172d54bb06a There are many other code snippets on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment