Which is the right pattern to check internet connection inside the application? - android

I created a broadcast receiver for monitoring my connection data and notify the user. I use an activity with a custom view to show a logo with no connection.
If I register the receiver in the manifest and the app is closed, when change the status of connection, the app is re-opened and I don't want this behavior.
What is the right pattern to follow?
Example? Link?
This is my receiver:
public class ConnectionHelper extends BroadcastReceiver {
static final String ACTION_CLOSE_ACTIVITY = "android.net.conn.CLOSE_ACTIVITY";
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();
if (!isConnected) {
Intent mainIntent = new Intent(context, NoConnectionActivity.class);
mainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(mainIntent);
} else {
Intent in = new Intent(ACTION_CLOSE_ACTIVITY);
context.sendBroadcast(in);
}
}
....
Thanks in advance for the response.
===UPDATE===
In the end, for my application I used NetworkEvents lib as suggested by #Anderson C Silva.
I created a simple application to help all the others who have doubts about how to solve this problem. github repository

I guess that a good solution for this issue is enable and disable the Broadcast programmatically. when app it is closed, so disable the Broadcast, something like this:
PackageManager pm = getPackageManager();
ComponentName compName =
new ComponentName(getApplicationContext(),
YourReceiver.class);
pm.setComponentEnabledSetting(
compName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
See more here:
Enabling and Disabling BroadcastReceivers at Runtime
Another possible solution to this case is use some lib EventBus, this way you register in your Activity to receiver the status of the network state from broadcast by Message.
This is a great lib to do this:
NetworkEvents
I hope this helps!

Related

Race condition when detecting connectivity status change in Android

I need to monitor and determine connectivity status changes in my Android app. For that, I have registered my class as a broadcast receiver:
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(this, filter);
Now, for determining the connectivity status, you can do the following:
#Override
public void onReceive(Context context, Intent intent) {
if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
return;
}
NetworkInfo aNetworkInfo =
intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if (aNetworkInfo == null) {
return;
}
boolean isConnected = aNetworkInfo.isConnected();
int networkType = aNetworkInfo.getType();
// by using isConnected & networkType, get the new connectivity status..
}
The issue is that ConnectivityManager.EXTRA_NETWORK_INFO is deprecated. Now, you are suggested to use the CONNECTIVITY_SERVICE with getActiveNetworkInfo(), something like that:
#Override
public void onReceive(Context context, Intent intent) {
if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
return;
}
ConnectivityManager connManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connManager == null) {
return;
}
NetworkInfo activeNetworkInfo = connManager.getActiveNetworkInfo();
boolean isConnected =
(activeNetworkInfo != null) && activeNetworkInfo.isConnected();
int networkType =
(activeNetworkInfo != null) ? activeNetworkInfo.getType() : -1;
// by using isConnected & networkType, get the new connectivity status..
}
This raises the following question:
In the 2nd implementation, when using the CONNECTIVITY_SERVICE and not the EXTRA_NETWORK_INFO:
Is there a chance for a race condition? As the onReceive is called asynchronously, when getting the network info from the connectivity service, may the connectivity state be different from the network info in the intent (as the connectivity might change in the meanwhile)?
Meaning, when using the intent, I am sure that the network info includes the data that triggered the onReceive, but when using the service - the network info might be different...?
If so, what's the best way to get the info that triggered the onReceive?
Also, if the only way to do so is to keep using the intent - doesn't that make 2 sources of truth? (one from the Connectivity Service, and one from the sent intent...)
UPDATE:
An example of the possible race condition:
Someone connected to WiFi and immediately disconnected from WiFi. This will result in 2 intents to be sent (one for connected to WiFi, and one for disconnecting from WiFi. More intents are actually sent, but I will focus on these 2). The possible race condition I am asking about is that: when we get the first intent (WiFi connected), the intent extra EXTRA_NETWORK_INFO will result in isConnected = true and networkType = TYPE_WIFI. But, is it possible that when I get the data from the Connectivity Service, as the onReceive is called asynchronously, the WiFi has already disconnected, resulting in isConnected = false and networkType = TYPE_WIFI while the intent still holds the right values for this call of onReceive? Or this will always happen fast enough so you get the right values from the Connectivity Service in the onReceive.. ?
My solution was sending a broadcast everytime connection changes adding an extra if the status of connection is up or down, hope it helps:
public class ConnectivityChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i(context.getClass().getName(), " Changed connection ");
context.sendBroadcast(new Intent(MyApplication.ACTION_CONNECTION_CHANGED)
.putExtra(MyApplication.INTENT_EXTRA_CONNECTION_STATUS,NetWorkUtils.isNetworkAvailable(context)));
}}
public static boolean isNetworkAvailable(Context context) {
ConnectivityManager cm =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null &&
activeNetwork.isConnectedOrConnecting();
}
Android manifest:
<receiver android:name=".ConnectivityChangeReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>

Start service when internet is active in android

How to start a service when internet is enabled?
I need to start the service when the internet is active state. I have application that communicate with the web application when internet is present,even offline the mobile need a communication,it will known by server at the time of internet comes active.
The answer is in your question. Just create a BroadcastReceiver to listen network state, when internet is okay, start server as usual.
public class NetworkBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
ConnectivityManager mgr = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = mgr.getActiveNetworkInfo();
if(networkInfo != null && networkInfo.isConnected()){
isNetworkConnected = true;
//do your work here
}
}
}}

Using Broadcastreceiver to get network state change

This is my first time using broadcast-receivers, and i thought it would be a little more straight forward than this. I have a class looking like this:
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo wifi = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
NetworkInfo mobile = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
boolean isConnected = wifi != null && wifi.isConnectedOrConnecting() || mobile != null && mobile.isConnectedOrConnecting();
if (isConnected) {
Log.d("Network Available ", "YES" + getResultCode());
}else{
Log.d("Network Available ", "NO" + getResultCode());
}
}
}
and i've registered it in my application like this
mReceiver = new NetworkChangeReceiver();
registerReceiver(mReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
And this is working OK, when i shut off my wifi, i get "NO" in log.d.. But how do i get something to "happen"? I want a Return-value or something which i can work with, for example if isConnected is false, then restart activity or something.
I've googled for days trying to understand what they are and how they work... Please help!
Well, the method is of type void, so a return value is out of the question. And besides, the calling class would be BroadcastManager or LocalBroadcastManager, so you wouldn't have any access to a potential return value.
You could register custom listeners inside your BroadcastReceiver, but that would mean keeping unnecessary references.
What I would do in your situation is fire off another broadcast with a custom "action" String in the "NO" block:
else{
Log.d("Network Available ", "NO" + getResultCode());
LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent(YOUR_CUSTOM_ACTION_NAME));
}
Register a listener for that event wherever needed and handle the behavior there.

Pause IntentService based on connectivity (Queue Intents)

After consulting Stackoverflow a lot I found this solution:
https://stackoverflow.com/a/11401196/2440358
Now I'm already using an IntentService which is handling the communication with the server and I've implemented a BroadcastReceiver which is looking for the current connectivity state.
IntentService:
public class CommunicationService extends IntentService {
public CommunicationService() {
super(CommunicationService.class.getName());
}
#Override
protected void onHandleIntent(Intent intent) {
String kind = intent.getExtras().getString("kind");
if ("LocationUpdate".equals(kind)) {
// send current Location to the server
}
}
BroadcastReceiver:
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
checkConnectionState(context);
}
public static boolean checkConnectionState(final Context context) {
final ConnectivityManager connectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager
.getActiveNetworkInfo();
Intent intent = new Intent(context, CommunicationService.class);
intent.putExtra("kind", "");
if (activeNetworkInfo != null && activeNetworkInfo.isConnected()) {
// start service
context.startService(intent);
return true;
} else {
// stop service
context.stopService(intent);
return false;
}
}
}
That's all working like a charm, but I don't know how to bring those two together like mentioned in the link above. I really would like to use that mentioned automatic queueing of the IntentService without.
Is there an easy way to make use of the IntentServices queueing and make it queue everything until the connectivity comes back?
Thanks in advance for your help :)
Edit: Now I solved it in a kinda dirty hack. The Application itself has a queue now, where the intents are added to in case they go wrong (internet connection loss during execution) or when there is no internet connection at all. The intents from that queue will be started again in the broadcastreceivers onReceive() when internet connection is available. I hope it helps someone ;)

Android: Stop/Start service depending on WiFi state?

In the android application that I'm designing, my service only needs to be running when the device is connected to the router (via WiFi obviously).
I'm really new to android, and what I've got so far has taken me forever to Achieve, so I'm really hoping for some pointers.
My service is set to start up when the phone starts up. Also when the Activity is launched it checks whether the service is running - and if not it starts it.
I'm just wondering what code I can put into my service to make it turn off if the WiFi state is lost - and what code I need to make the service start once a WiFi connection becomes active?
Thanks! :)
You can create a BroadcastReceiver that handles wifi connection changes.
To be more precise, you will want to create a class - say NetWatcher:
public class NetWatcher extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//here, check that the network connection is available. If yes, start your service. If not, stop your service.
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo();
if (info != null) {
if (info.isConnected()) {
//start service
Intent intent = new Intent(context, MyService.class);
context.startService(intent);
}
else {
//stop service
Intent intent = new Intent(context, MyService.class);
context.stopService(intent);
}
}
}
}
(changing MyService to the name of your service).
Also, in your AndroidManifest, you need to add the following lines:
<receiver android:name="com.example.android.NetWatcher">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
(changing com.example.android to the name of your package).
As #Phil stated, you should extend BroadcastReceiver, and in onReceive method start or stop the service. Something like:
class ConnectionChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
if (activeNetInfo != null && activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI) {
//start service
} else {
//stop service
}
}
}
You can make this a private class of your activity, and register receiver on activity create, and unregister it on activity destroy.
More useful information is provided here: Determining and Monitoring the Connectivity Status
To start/stop your service when supplicant Wifi state is ok/nok:
register a BroadcastReceiver to recieve WIFI state change broadcasted intents
inside your BroadCastReceiver check the intent validity then start your service
So register your broadcast receiver to receive WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION.
Add permission android.permission.CHANGE_WIFI_STATE or android.permission.ACCESS_NETWORK_STATE. I'm not sure if it is necessary or not.
Then a sample broadcast receiver code could be:
public class MyWifiStatereceiver extends BroadcastReceiver {
//Other stuff here
#Override
public void onReceive(Context context, Intent intent) {
Intent srvIntent = new Intent();
srvIntent.setClass(MyService.class);
boolean bWifiStateOk = false;
if (WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION.equals(intent.getAction()) {
//check intents and service to know if all is ok then set bWifiStateOk accordingly
bWifiStateOk = ...
} else {
return ; // do nothing ... we're not in good intent context doh !
}
if (bWifiStateOk) {
context.startService(srvIntent);
} else {
context.stopService(srvIntent);
}
}
}

Categories

Resources