I am looking for a way to check and to listen to my internet connection but since the latest Android version doesn't support registering a broadcast in Manifest, I am looking for a way to implement something that works on all the Android versions. So far I couldn't find any solutions.
I tried adding a Broadcast intent filter into my Manifest file but that's not allowed in the more recent Android versions.
<receiver
android:name="utilities.NetworkStateChangeReceiver"
android:exported="true"
android:enabled="true"
android:label="NetworkConnection" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.net.wifi.STATE_CHANGE"/>
</intent-filter>
</receiver>
public class NetworkStateChangeReceiver extends BroadcastReceiver {
public static final String NETWORK_AVAILABLE_ACTION = "NetworkAvailable";
public static final String IS_NETWORK_AVAILABLE = "isNetworkAvailable";
#Override
public void onReceive(Context context, Intent intent) {
Intent networkStateIntent = new Intent(NETWORK_AVAILABLE_ACTION);
networkStateIntent.putExtra(IS_NETWORK_AVAILABLE, isConnectedToInternet(context));
LocalBroadcastManager.getInstance(context).sendBroadcast(networkStateIntent);
}
private boolean isConnectedToInternet(Context context) {
final ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
boolean isMobile = false, isWifi = false;
NetworkInfo[] infoAvailableNetworks = cm.getAllNetworkInfo();
if (infoAvailableNetworks != null) {
for (NetworkInfo network : infoAvailableNetworks) {
if (network.getType() == ConnectivityManager.TYPE_WIFI) {
if (network.isConnected() && network.isAvailable())
isWifi = true;
}
if (network.getType() == ConnectivityManager.TYPE_MOBILE) {
if (network.isConnected() && network.isAvailable())
isMobile = true;
}
}
}
return isMobile || isWifi;
}
}
My receiver is not able to receive a broadcast
I'm using pretty much the same logic with IntentFilter and it works for me pretty good without registering it in the Manifest file.
Interface:
public interface IReceiverStateChange {
void register(BroadcastReceiver broadcastReceiver);
void unregister(BroadcastReceiver broadcastReceiver);
}
Implementation:
public class NetworkReceiverStateChange implements IReceiverStateChange {
private Context mContext;
private Boolean mIsRegistered = false;
public NetworkReceiverStateChange(Context context) {
mContext = context;
}
#Override
public void register(BroadcastReceiver broadcastReceiver) {
if (!mIsRegistered) {
IntentFilter netWorkIntentFilter = new
IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
mContext.registerReceiver(broadcastReceiver, netWorkIntentFilter);
mIsRegistered = true;
}
}
#Override
public void unregister(BroadcastReceiver broadcastReceiver) {
if (mIsRegistered) {
mContext.unregisterReceiver(broadcastReceiver);
mIsRegistered = false;
}
}
}
Register in the desired activity:
if (mNetworkStateChange == null) {
mNetworkStateChange = new NetworkReceiverStateChange(this);
}
mNetworkStateChange.register(mNetworkBroadcastReceiver);
Unregister in onDestroy:
if (mNetworkStateChange != null) {
mNetworkStateChange.unregister(mNetworkBroadcastReceiver);
}
The BroadcastReceiver Obj:
//The CONNECTIVITY_ACTION broadcast seems to be sticky on some devices (even
though the documentation implies that it is not).
// This means that when you register the receiver it will immediately call
onReceive() with the most recently sent broadcast.
private final BroadcastReceiver mNetworkBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action != null && action.matches("android.net.conn.CONNECTIVITY_CHANGE")) {
<DO SOMETHING>
}
}
};
Hope it helps :)
If you want to check your internet connection all of your activities you can follow below code :-
NetworkSchedulerService.java
public class NetworkSchedulerService extends JobService implements
ConnectivityReceiver.ConnectivityReceiverListener {
private static final String TAG = NetworkSchedulerService.class.getSimpleName();
private ConnectivityReceiver mConnectivityReceiver;
#Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "Service created");
prefManager = PrefManager.getInstance(this);
mConnectivityReceiver = new ConnectivityReceiver(this);
}
/**
* When the app's NetworkConnectionActivity is created, it starts this service. This is so that the
* activity and this service can communicate back and forth. See "setUiCallback()"
*/
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand");
return START_NOT_STICKY;
}
#Override
public boolean onStartJob(JobParameters params) {
Log.i(TAG, "onStartJob" + mConnectivityReceiver);
registerReceiver(mConnectivityReceiver, new IntentFilter(CONNECTIVITY_ACTION));
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
Log.i(TAG, "onStopJob");
unregisterReceiver(mConnectivityReceiver);
return true;
}
#Override
public void onNetworkConnectionChanged(boolean isConnected) {
if(isConnected){
Toast.makeText(this,"connected to internet",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this,"no internet connection",Toast.LENGTH_SHORT).show();
}
}
}
In manifest file
<service
android:name=".NetworkSchedulerService"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE"/>```
create a Application class
class MyApplication extends Application {
override fun onCreate() {
super.onCreate()
scheduleJob()
}
override fun onStop() {
super.onStop()
// A service can be "started" and/or "bound". In this case, it's "started" by this Activity
// and "bound" to the JobScheduler (also called "Scheduled" by the JobScheduler). This call
// to stopService() won't prevent scheduled jobs to be processed. However, failing
// to call stopService() would keep it alive indefinitely.
stopService(Intent(this, NetworkSchedulerService::class.java))
}
override fun onStart(){
val startServiceIntent = Intent(this, NetworkSchedulerService::class.java)
startService(startServiceIntent)
}
private fun scheduleJob() {
val myJob = JobInfo.Builder(0, ComponentName(this, NetworkSchedulerService::class.java))
.setRequiresCharging(true)
.setMinimumLatency(1000)
.setOverrideDeadline(2000)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setPersisted(true)
.build()
val jobScheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
jobScheduler.schedule(myJob)
}
}
define application class in manifest file
BroadcastReceiver class ->
public class ConnectivityReceiver extends BroadcastReceiver {
private ConnectivityReceiverListener mConnectivityReceiverListener;
ConnectivityReceiver(ConnectivityReceiverListener listener) {
mConnectivityReceiverListener = listener;
}
#Override
public void onReceive(Context context, Intent intent) {
mConnectivityReceiverListener.onNetworkConnectionChanged(isConnected(context));
}
public static boolean isConnected(Context context) {
ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
}
public interface ConnectivityReceiverListener {
void onNetworkConnectionChanged(boolean isConnected);
}
}
**onNetworkConnectionChanged will notify when internet is connected or not (NetworkSchedulerService.java)
Don't define BroadCastReceiver in manifest file. make sure to provide internect permission , CHANGE_NETWORK_STATE,ACCESS_NETWORK_STATE
**
I hope this will help you. Let me know if there is any problem. Happy Coding :-)
Related
I want to convert Java code to C# but facing problem to do so
public class MyService extends Service {
static final String CONNECTIVITY_CHANGE_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
NotificationManager manager ;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Let it continue running until it is stopped.
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
IntentFilter filter = new IntentFilter();
filter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (CONNECTIVITY_CHANGE_ACTION.equals(action)) {
//check internet connection
if (!ConnectionHelper.isConnectedOrConnecting(context)) {
if (context != null) {
boolean show = false;
if (ConnectionHelper.lastNoConnectionTs == -1) {//first time
show = true;
ConnectionHelper.lastNoConnectionTs = System.currentTimeMillis();
} else {
if (System.currentTimeMillis() - ConnectionHelper.lastNoConnectionTs > 1000) {
show = true;
ConnectionHelper.lastNoConnectionTs = System.currentTimeMillis();
}
}
if (show && ConnectionHelper.isOnline) {
ConnectionHelper.isOnline = false;
Log.i("NETWORK123","Connection lost");
//manager.cancelAll();
}
}
} else {
Log.i("NETWORK123","Connected");
showNotifications("APP" , "It is working");
// Perform your actions here
ConnectionHelper.isOnline = true;
}
}
}
};
registerReceiver(receiver,filter);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
}
}
This part I am not getting which coming in middle of code
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent)
{
}
};
You probably want to see a more comprehensive answer for this to see how the given suggestions all fits together:
public class MyService : Service
{
internal const string CONNECTIVITY_CHANGE_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
internal NotificationManager manager;
public override IBinder onBind(Intent intent)
{
return null;
}
public override int onStartCommand(Intent intent, int flags, int startId)
{
// Let it continue running until it is stopped.
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
IntentFilter filter = new IntentFilter();
filter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
BroadcastReceiver receiver = new BroadcastReceiverAnonymousInnerClass();
registerReceiver(receiver,filter);
return START_STICKY;
}
private class BroadcastReceiverAnonymousInnerClass : BroadcastReceiver
{
public override void onReceive(Context context, Intent intent)
{
string action = intent.Action;
if (CONNECTIVITY_CHANGE_ACTION.Equals(action))
{
//check internet connection
if (!ConnectionHelper.isConnectedOrConnecting(context))
{
if (context != null)
{
bool show = false;
if (ConnectionHelper.lastNoConnectionTs == -1)
{ //first time
show = true;
ConnectionHelper.lastNoConnectionTs = DateTimeHelper.CurrentUnixTimeMillis();
}
else
{
if (DateTimeHelper.CurrentUnixTimeMillis() - ConnectionHelper.lastNoConnectionTs > 1000)
{
show = true;
ConnectionHelper.lastNoConnectionTs = DateTimeHelper.CurrentUnixTimeMillis();
}
}
if (show && ConnectionHelper.isOnline)
{
ConnectionHelper.isOnline = false;
Log.i("NETWORK123","Connection lost");
//manager.cancelAll();
}
}
}
else
{
Log.i("NETWORK123","Connected");
showNotifications("APP", "It is working");
// Perform your actions here
ConnectionHelper.isOnline = true;
}
}
}
}
public override void onDestroy()
{
base.onDestroy();
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
}
}
internal static class DateTimeHelper
{
private static readonly System.DateTime Jan1st1970 = new System.DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc);
public static long CurrentUnixTimeMillis()
{
return (long)(System.DateTime.UtcNow - Jan1st1970).TotalMilliseconds;
}
}
I think you would do something like this
var receiver = new MyReceiver();
public class MyReceiver : BroadcastReceiver
{
public override void onReceive(Context context, Intent intent)
{
}
}
Since C# does not allow anonymous classes you will have to explicitly create it and then pass the data that you need there from this class.
[BroadcastReceiver(Enabled = true, Exported = false)]
public class SampleReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
// Do stuff here.
}
}
Then use it like:
var receiver = new SampleReceiver();
I am implementing an app who needs an internet connection. If there is no internet connection, a "no connection" message will be displayed on different ways, depending on the activity.
To do this, I have the following class:
public class NetworkAvailability {
private static final String NETWORK_AVAILABILITY_ACTION = "com.toast.NETWORK_AVAILABILITY_ACTION";
private ConnectivityManager connectivityManager;
private ConnectivityManager.NetworkCallback networkCallback;
private static NetworkAvailability instance;
private NetworkAvailability() {
}
public static NetworkAvailability getInstance(){
if(instance == null){
instance = new NetworkAvailability();
}
return instance;
}
private static boolean isAvailable(Context context) {
ConnectivityManager cm =(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null && activeNetwork.isConnected();
}
public void registerNetworkAvailability(final Context context, BroadcastReceiver networkAvailabilityReceiver) {
context.registerReceiver(networkAvailabilityReceiver, new IntentFilter(NETWORK_AVAILABILITY_ACTION));
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
context.registerReceiver(connectivityChangeReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
} else{
connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder builder = new NetworkRequest.Builder();
networkCallback = new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
context.sendBroadcast(getNetworkAvailabilityIntent(true));
}
#Override
public void onLost(Network network) {
context.sendBroadcast(getNetworkAvailabilityIntent(false));
}
};
connectivityManager.registerNetworkCallback(builder.build(), networkCallback);
if(isAvailable(context)){
context.sendBroadcast(getNetworkAvailabilityIntent(true));
} else{
context.sendBroadcast(getNetworkAvailabilityIntent(false));
}
}
}
public void unregisterNetworkAvailability(Context context, BroadcastReceiver networkAvailabilityReceiver){
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
context.unregisterReceiver(connectivityChangeReceiver);
} else{
connectivityManager.unregisterNetworkCallback(networkCallback);
}
context.unregisterReceiver(networkAvailabilityReceiver);
}
public BroadcastReceiver connectivityChangeReceiver = new BroadcastReceiver() {
#Override
public void onReceive(#NonNull Context context, #NonNull Intent intent) {
if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {
context.sendBroadcast(getNetworkAvailabilityIntent(false));
} else {
context.sendBroadcast(getNetworkAvailabilityIntent(true));
}
}
};
#NonNull
private Intent getNetworkAvailabilityIntent(boolean isNetworkAvailable) {
Intent intent = new Intent(NETWORK_AVAILABILITY_ACTION);
intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, !isNetworkAvailable);
return intent;
}
}
How can I now use the BroadcastReceiver from each Activity?
What I did was setting the broadcastReceiver on the Manifest:
<receiver
android:name=".data.sync.CatchConnectionChangesReceiver"
android:label="Upload cached images broadcast receiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
Then I have the class:
class CatchConnectionChangesReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (Util.isNetworkAvailable()) {
// Do whatever you want to do when network is available
}
}
}
The receiver is going to be activated from every activity, you don´t need to register it on each
In Util.isNetworkAvailable() I have the same as in your isAvailable() method
Update according to first comment
If you want to do something like:
if (isConnected) {
// Do something here like view.setVisibility(View.Visible)
}
You just have your isAvailable() method public, as it´s already static, you can do this from any activity you want:
if (NetworkAvailability.isAvailable(this)) {
// Do something here like view.setVisibility(View.Visible)
}
For this last thing you do not need the broadcast receiver
I am trying to update the UI according to change of a variable in BroadcastReceiver. Thus, I need to call a method (to get the variable I mentioned) of a class which extends BroadcastReceiver in MainActivity depending on but I cannot get the true return value in any way.
The class which extends BroadcastReceiver is this:
public class ProviderChangeReceiver extends BroadcastReceiver {
private static boolean isProviderActive;
#Override
public void onReceive(Context context, Intent intent) {
LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) && lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
Log.v("-> ", "GPS + NETWORK");
isProviderActive = true;
}
else if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) && !lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
Log.v("-> ", "GPS");
isProviderActive = true;
}
else if (lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER) && !lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Log.v("-> ", "NETWORK");
isProviderActive = true;
}
else
{
Log.v("-> ", "DISCONNECT");
isProviderActive = false;
}
}
public static boolean isProviderActive(){
return isProviderActive;
}
}
I need to get true value of isProviderActive to use in this part of MainActivity:
...
private class ProviderChangeReceiver_updateUI extends ProviderChangeReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
MapsActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Log.v("-A", ""+ isProviderActive());
if (isProviderActive())
originButton.setVisibility(View.VISIBLE);
else
originButton.setVisibility(View.INVISIBLE);
}
});
}
}
I know that indicating isProviderActive as static is not a good approach but I just want to observe its changes. As you guess, I got nonsensical return values all the time. To values of boolean isProviderActive without problem, what do you advise?
Edit: My temporary solution to update UI according to changes in BroadcastReceiver.
Forget about creating a separate class for ProviderChangeReceiver. Instead of the code segment above, following segment should be added in MainActivity. Also, it goes without saying that there is the initialization of ProviderChangeReceiver in onCreate().
...
private class ProviderChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
MapsActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Log.v("COUNT: ", "" + count++);
if (isLocationProviderActive()) {
originButton.getBackground().setAlpha(220);
originButton.setEnabled(true);
//marker.setVisible(true);
}
else {
originButton.getBackground().setAlpha(77);
originButton.setEnabled(false);
marker.setVisible(false);
}
}
});
}
}
private boolean isLocationProviderActive(){
if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) && lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER))
return true;
return false;
}
Of course then register the receiver in onCreate() as well:
registerReceiver(pcr, new IntentFilter("android.location.PROVIDERS_CHANGED"));
The reason that every time isProvidrActive changed the whole activity got regenerated is because I sent the intent using context.startActivity(i) but rather this time we send the intent using contect.sendBroadcast(i) to the ProviderChangeReceiver_updateUI inner class which update only desired part of the UI. So below is the new code.
private static boolean isProviderActive;
#Override
public void onReceive(Context context, Intent intent) {
LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) && lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
Log.v("-> ", "GPS + NETWORK");
isProviderActive = true;
}
else if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) && !lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
Log.v("-> ", "GPS");
isProviderActive = true;
}
else if (lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER) && !lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Log.v("-> ", "NETWORK");
isProviderActive = true;
}
else
{
Log.v("-> ", "DISCONNECT");
isProviderActive = false;
}
//Send value of isProviderActive to ProviderChangeReceiver_updateUI
Intent i = new Intent(context, ProviderChangeReceiver_updateUI.class);
i.putExtra("isProvidrActv", isProviderActive);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.sendBroadcast(i);
}
Edit your manifest file to enable the inner class ProviderChangeReceiver_updateUI to listen for broadcast sent by our broadcastReciever, add the following entry to manifest
<receiver android:name="<package-name>.MainActivity$ProviderChangeReceiver_updateUI"
android:enabled="true" >
<intent-filter>
</intent-filter>
</receiver>
the $ sign indicates inner class. No need to add intent-filters unless required.
And in your ProviderChangeReceiver_updateUI class in the onReceive() method get the value of isProviderActive
...
//changed the identifiers from private to public static and the class extends //BroadcastReceiver
public static class ProviderChangeReceiver_updateUI extends BroadcastReceiver {
//Empty constructor to prevent exception can't instantiate no empty constructor
public ProviderChangeReceiver_updateUI(){
}
//Removed the final keyword from handler
private Handler handler; // Handler used to execute code on the UI thread
public ProviderChangeReceiver_updateUI(Handler handler) {
this.handler = handler;
}
#Override
public void onReceive(final Context context, final Intent intent) {
boolean isProvidrActv = intent.getBooleanExtra("isProvidrActv", false);
//mapsActivity is a global static object of the class MapsActivity<br/>
//instantiate it the onCreate() method of mainactivity for ex:<br/>
/*public class MapsActivity extends Activity{<br/>
static MapsActivity mapsActivity;
#Override
protected void onCreate(Bundle savedInstancestate){
ma = new MapsActivity();
}*/
mapsActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
if (isProvidrActv)
originButton.setVisibility(View.VISIBLE);
else
originButton.setVisibility(View.INVISIBLE);
}
});
}
}
I think a nice way to handle something like this is with an eventbus.
Take a look at Squares Otto library.
In your broadcast receiver you would publish the change event and then in your activity you would subscribe to the event and update the ui.
Based on the context of your question, I think you would be able to avoid the broadcast receiver entirely, since I suspect you have something watching your provider and then broadcasting the event.
Update: (based on comments)
I think the way this would work would be something like this
In the code that detects the change in location provider:
if (bothProvidersAreStopped()) {
bus.publish(new BothProvidersStoppedEvent());
} else if (onlyNetworkProviderIsStopped() {
bus.publish(new NetworkProviderStoppedEvent());
} else if (onlyGpsProviderIsStopped() {
bus.publish(new GpsProviderStoppedEvent());
}
in your activity
#Subscribe public void onBothProvidersStopped(BothProvidersStopped event) {
// handle case were both providers just stopped
}
#Subscribe public void onNetworkProvidersStopped(BothProvidersStopped event) {
// handle case were network provider just stopped
}
#Subscribe public void onGpsProvidersStopped(BothProvidersStopped event) {
// handle case were gps provider just stopped
}
I already have this code which listens to connectivity change -
public class NetworkStateReceiver extends BroadcastReceiver
{
public void onReceive(Context context, Intent intent)
{
Log.d("app","Network connectivity change");
if(intent.getExtras() != null)
{
NetworkInfo ni = (NetworkInfo) intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO);
if(ni != null && ni.getState() == NetworkInfo.State.CONNECTED)
{
Log.i("app", "Network " + ni.getTypeName() + " connected");
}
}
if(intent.getExtras().getBoolean(ConnectivityManager.EXTRA_NO_CONNECTIVITY, Boolean.FALSE))
{
Log.d("app", "There's no network connectivity");
}
}
}
And I check Internet connectivity using this code - Internet Check
But the problem is that if network suddenly loses internet connection without any connectivity change, this code is useless. Is there any way to create Broadcast Receiver listener for Internet connectivity change? I have a web app and sudden Internet connectivity changes can cause problems.
Try this
public class NetworkUtil {
public static final int TYPE_WIFI = 1;
public static final int TYPE_MOBILE = 2;
public static final int TYPE_NOT_CONNECTED = 0;
public static final int NETWORK_STATUS_NOT_CONNECTED = 0;
public static final int NETWORK_STATUS_WIFI = 1;
public static final int NETWORK_STATUS_MOBILE = 2;
public static int getConnectivityStatus(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
if (null != activeNetwork) {
if(activeNetwork.getType() == ConnectivityManager.TYPE_WIFI)
return TYPE_WIFI;
if(activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE)
return TYPE_MOBILE;
}
return TYPE_NOT_CONNECTED;
}
public static int getConnectivityStatusString(Context context) {
int conn = NetworkUtil.getConnectivityStatus(context);
int status = 0;
if (conn == NetworkUtil.TYPE_WIFI) {
status = NETWORK_STATUS_WIFI;
} else if (conn == NetworkUtil.TYPE_MOBILE) {
status = NETWORK_STATUS_MOBILE;
} else if (conn == NetworkUtil.TYPE_NOT_CONNECTED) {
status = NETWORK_STATUS_NOT_CONNECTED;
}
return status;
}
}
And for the BroadcastReceiver
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
int status = NetworkUtil.getConnectivityStatusString(context);
Log.e("Sulod sa network reciever", "Sulod sa network reciever");
if ("android.net.conn.CONNECTIVITY_CHANGE".equals(intent.getAction())) {
if (status == NetworkUtil.NETWORK_STATUS_NOT_CONNECTED) {
new ForceExitPause(context).execute();
} else {
new ResumeForceExitPause(context).execute();
}
}
}
}
Don't forget to put this into your AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<receiver
android:name="NetworkChangeReceiver"
android:label="NetworkChangeReceiver" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
</intent-filter>
</receiver>
Hope this will help you Cheers!
ConnectivityAction is deprecated in api 28+. Instead you can use registerDefaultNetworkCallback as long as you support api 24+.
In Kotlin:
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
connectivityManager?.let {
it.registerDefaultNetworkCallback(object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
//take action when network connection is gained
}
override fun onLost(network: Network?) {
//take action when network connection is lost
}
})
}
Here's the Java code using registerDefaultNetworkCallback (and registerNetworkCallback for API < 24):
ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
// network available
}
#Override
public void onLost(Network network) {
// network unavailable
}
};
ConnectivityManager connectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
connectivityManager.registerDefaultNetworkCallback(networkCallback);
} else {
NetworkRequest request = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).build();
connectivityManager.registerNetworkCallback(request, networkCallback);
}
Update:
Apps targeting Android 7.0 (API level 24) and higher do not receive
CONNECTIVITY_ACTION broadcasts if they declare the broadcast receiver
in their manifest. Apps will still receive CONNECTIVITY_ACTION
broadcasts if they register their BroadcastReceiver with
Context.registerReceiver() and that context is still valid.
You need to register the receiver via registerReceiver() method:
IntentFilter intentFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
mCtx.registerReceiver(new NetworkBroadcastReceiver(), intentFilter);
This should work:
public class ConnectivityChangeActivity extends Activity {
private BroadcastReceiver networkChangeReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("app","Network connectivity change");
}
};
#Override
protected void onResume() {
super.onResume();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(networkChangeReceiver, intentFilter);
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(networkChangeReceiver);
}
}
I used this method as a connection listener. Working for Lolipop+, Android JAVA language.
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest networkRequest = new NetworkRequest.Builder().build();
connectivityManager.registerNetworkCallback(networkRequest, new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
super.onAvailable(network);
Log.i("Tag", "active connection");
}
#Override
public void onLost(Network network) {
super.onLost(network);
Log.i("Tag", "losing active connection");
isNetworkConnected();
}
});
}
private boolean isNetworkConnected() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (!(cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected())) {
//Do something
return false;
}
return true;
}
And also add this permission in your Android Manifest.xml
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Hello from the year 2022.
In my custom view model I observe network status changes like this:
public class MyViewModel extends AndroidViewModel {
private final MutableLiveData<Boolean> mConnected = new MutableLiveData<>();
public MyViewModel(Application app) {
super(app);
ConnectivityManager manager = (ConnectivityManager)app.getSystemService(Context.CONNECTIVITY_SERVICE);
if (manager == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
mConnected.setValue(true);
return;
}
NetworkRequest networkRequest = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build();
manager.registerNetworkCallback(networkRequest, new ConnectivityManager.NetworkCallback() {
Set<Network> availableNetworks = new HashSet<>();
public void onAvailable(#NonNull Network network) {
availableNetworks.add(network);
mConnected.postValue(!availableNetworks.isEmpty());
}
public void onLost(#NonNull Network network) {
availableNetworks.remove(network);
mConnected.postValue(!availableNetworks.isEmpty());
}
public void onUnavailable() {
availableNetworks.clear();
mConnected.postValue(!availableNetworks.isEmpty());
}
});
}
#NonNull
public MutableLiveData<Boolean> getConnected() {
return mConnected;
}
}
And then in my Activity or Fragment I can change the UI by observing:
#Override
protected void onCreate(Bundle savedInstanceState) {
MyViewModel vm = new ViewModelProvider(this).get(MyViewModel.class);
vm.getConnected().observe(this, connected -> {
// TODO change GUI depending on the connected value
});
}
first add dependency in your code as implementation 'com.treebo:internetavailabilitychecker:1.0.4'
implements your class with InternetConnectivityListener.
public class MainActivity extends AppCompatActivity implements InternetConnectivityListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InternetAvailabilityChecker.init(this);
mInternetAvailabilityChecker = InternetAvailabilityChecker.getInstance();
mInternetAvailabilityChecker.addInternetConnectivityListener(this);
}
#Override
public void onInternetConnectivityChanged(boolean isConnected) {
if (isConnected) {
alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle(" internet is connected or not");
alertDialog.setMessage("connected");
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialog.show();
}
else {
alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle("internet is connected or not");
alertDialog.setMessage("not connected");
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialog.show();
}
}
}
I have noticed that no one mentioned WorkManger solution which is better and support most of android devices.
You should have a Worker with network constraint AND it will fired only if network available, i.e:
val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
val worker = OneTimeWorkRequestBuilder<MyWorker>().setConstraints(constraints).build()
And in worker you do whatever you want once connection back, you may fire the worker periodically .
i.e:
inside dowork() callback:
notifierLiveData.postValue(info)
According to the official docs:
Define network request
private val networkRequest = NetworkRequest.Builder().apply {
// To check wifi and cellular networks for internet availability
addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Capabilities can be verified starting Android 6.0.
// For a network with NET_CAPABILITY_INTERNET,
// it means that Internet connectivity was successfully detected
addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// Indicates that this network is available for use by apps,
// and not a network that is being kept up in the background
// to facilitate fast network switching.
addCapability(NetworkCapabilities.NET_CAPABILITY_FOREGROUND)
}
}.build()
Configure a network callback
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
private val networks = mutableListOf<Network>()
override fun onAvailable(network: Network) {
super.onAvailable(network)
networks.add(network)
Log.d("Has network --->", networks.any().toString())
}
override fun onLost(network: Network) {
super.onLost(network)
networks.remove(network)
Log.d("Has network --->", networks.any().toString())
}
}
Register for network updates
val connectivityService =
applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
connectivityService.registerNetworkCallback(networkRequest, networkCallback)
ref https://developer.android.com/training/monitoring-device-state/connectivity-status-type
To specify the transport type of the network, such as Wi-Fi or
cellular connection, and the currently connected network's
capabilities, such as internet connection, you must configure a
network request.
Declare a NetworkRequest that describes your app’s network connection
needs. The following code creates a request for a network that is
connected to the internet and uses either a Wi-Fi or cellular
connection for the transport type.
add this in onCreate
NetworkRequest networkRequest = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.build();
Configure a network callback When you register the NetworkRequest with
the ConnectivityManager, you must implement a NetworkCallback to
receive notifications about changes in the connection status and
network capabilities.
The most commonly implemented functions in the NetworkCallback include
the following:
onAvailable() indicates that the device is connected to a new network
that satisfies the capabilities and transport type requirements
specified in the NetworkRequest. onLost() indicates that the device
has lost connection to the network. onCapabilitiesChanged() indicates
that the capabilities of the network have changed. The
NetworkCapabilities object provides information about the current
capabilities of the network.
add listener
private ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(#NonNull Network network) {
super.onAvailable(network);
}
#Override
public void onLost(#NonNull Network network) {
super.onLost(network);
}
#Override
public void onCapabilitiesChanged(#NonNull Network network, #NonNull NetworkCapabilities networkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities);
final boolean unmetered = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
}};
Register for network updates After you declare the NetworkRequest and
NetworkCallback, use the requestNetwork() or registerNetworkCallback()
functions to search for a network to connect from the device that
satisfies the NetworkRequest. The status is then reported to the
NetworkCallback.
Register in onCreate
ConnectivityManager connectivityManager =
(ConnectivityManager) getSystemService(ConnectivityManager.class);
connectivityManager.requestNetwork(networkRequest, networkCallback);
implementation 'com.treebo:internetavailabilitychecker:1.0.1'
public class MyApp extends Application {
#Override
public void onCreate() {
super.onCreate();
InternetAvailabilityChecker.init(this);
}
#Override
public void onLowMemory() {
super.onLowMemory();
InternetAvailabilityChecker.getInstance().removeAllInternetConnectivityChangeListeners();
}
}
I have a MyService class which implements custom CallReceiver.Listener . The problem is listener registration called in MyService is not working. mListener in CallReceiver is always null. It proves that listener was not registerd, but I have no idea why is that.
MyService class (an extract):
public class MyService extends Service implements CallReceiver.Listener {
CallReceiver mCallReceiver;
public int onStartCommand (Intent intent, int flags, int startId) {
serviceStart();
return startId;
}
// starting service
public void serviceStart() {
mCallReceiver = new CallReceiver();
// registering listener for CallReceiver
mCallReceiver.registerListener(this);
}
public void onPhoneStateChange(boolean state) {
if (state) {
Log.v("onPhoneStateChange", "service destroyed");
serviceDestroy();
} else {
// serviceStart();
}
}
}
CallReceiver class:
public class CallReceiver extends BroadcastReceiver {
private boolean isRinging = false;
private Listener mListener = null;
// interface declaration
public interface Listener {
public void onPhoneStateChange(boolean state);
}
// listener registration
public void registerListener (Listener listener) {
mListener = listener;
}
#Override
public void onReceive(Context context, Intent intent) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if(TelephonyManager.EXTRA_STATE_RINGING.equals(state)) {
// do something while ringing
Log.v("phone", "ringing");
isRinging = true;
}
else if(TelephonyManager.EXTRA_STATE_IDLE.equals(state)) {
//do something when the call ends
Log.v("phone", "idle");
isRinging = false;
}
if(mListener != null) {
// onPhoneStateChange is not called because mListener is null
mListener.onPhoneStateChange(isRinging);
}
}
}
You should register your receiver dynamically.
// registering listener for CallReceiver
mCallReceiver.registerListener(this);
IntentFilter filter = new IntentFilter("your.Intent");
registerReceiver (mCallReceiver, filter);
Also, in your services onDestroy(), don't forget to unregister it.
#Override
public void onDestroy ()
{
try {
unregisterReceiver (broadcastReceiver);
}
catch (IllegalArgumentException e){}
catch (NullPointerException ne){}
super.onDestroy();
}