I have a service that runs upon boot completion. This service requires internet connectivity. What's the best practice for waiting for the device to connect to the internet? Mobile of wifi doesn't really matter.
My current solution involves a while loop that just checks ConnectivityManager until one of the networks becomes available, but this feels vulgar.
Is there a better way to do this?
but this feels vulgar
Indeed :D
Your receiver wakes your wakeful intent service (probably a simple intent service would do, as the phone does not sleep while booting AFAIK)
service registers a receiver for connectivity
service waits on a CountDownLatch
the receiver wakes the service up when the wifi is connected
Skeleton code : https://stackoverflow.com/a/19968708/281545 - your case is simpler as you do not have to wake the wifi, hold wifi locks etc. Otherwise (including the case this takes long and radios/CPU sleep - in which case a simple intent service won't do) between 2 and 3 you would need to :
2a. service acquires a wifi lock
2b. service calls reconnect(), reassociate() and whatever is needed (this may be device specific)
You could use a BroadcastReceiver:
private class ConnectionMonitor extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION))
return;
boolean noConnectivity = intent.getBooleanExtra(
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
NetworkInfo aNetworkInfo = (NetworkInfo) intent
.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if (!noConnectivity) {
if ((aNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE)
|| (aNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI)) {
// start your service stuff here
}
} else {
if ((aNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE)
|| (aNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI)) {
// stop your service stuff here
}
}
}
}
Then, you instantiate somewhere in your code:
ConnectionMonitor connectionMonitor = new ConnectionMonitor();
registerReceiver(connectionMonitor, intentFilter);
Note: this code comes from Detect 3G or Wifi Network restoration
Related
My android application is based on network connection i.e WIFI/Mobile Network. It works fine when my mobile is connected to internet but when internet connection disconnected it stops working (obesely) and it still stop working after my mobile again connected to internet.
I wish to (re)start my application automatically whenever internet connection is (re)established.
You can check the network state using broadcast receiver. Whenever the network is available, you can start your application.
First, create a background service and start your service when the device boots up. Now, in this service, register a broadcast receiver and monitor the network state. If the network is available, you can start your application; and if unavailable, you can close it.
Please refer to the code below for broadcast receiver.
public class BroadCastSampleActivity extends Activity
{
/** Called when the activity is first created. */
#Override
protected void onCreate(Bundle savedInstanceState)
{
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.registerReceiver(this.mConnReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
private BroadcastReceiver mConnReceiver = new BroadcastReceiver()
{
public void onReceive(Context context, Intent intent)
{
boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
String reason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);
boolean isFailover = intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false);
NetworkInfo currentNetworkInfo = (NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
NetworkInfo otherNetworkInfo = (NetworkInfo) intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
if(currentNetworkInfo.isConnected())
{
Toast.makeText(getApplicationContext(), "Connected", Toast.LENGTH_LONG).show();
}
else
{
Toast.makeText(getApplicationContext(), "Not Connected", Toast.LENGTH_LONG).show();
}
}
};
}
I think you must need to checking continue for network connections, that means you need to check for internet connection in background tasks. Android Services is better option for that, create one Service and start it when your app starts, inside that just do one code and that is for checking Internet Connectivity, when it lost, do some task and when it found you can do whatever you want. So I suggest you to use services and get your task done.
Here are some links to refer.
http://www.tutorialspoint.com/android/android_services.htm
http://www.vogella.com/tutorials/AndroidServices/article.html
I think you should create a spread thread or service in background for checking network connection after some interval . use following code in thread or service whatever you want to create .
NetworkInfo i = conMgr.getActiveNetworkInfo();
if (i == null)
return false;
if (!i.isConnected())
return false;
if (!i.isAvailable())
return false;
return true;
I have written the following code for detecting the network status from within the BroadcastReceiver. I start a service when the network is available and stop the service when the network is not available.
I have the following class level variable.
private boolean IsNetworkAlreadyConnected = false;
Within onCreate method of the main class I start the service if the internet is available.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (InternetConnectivity.isConnected(MainActivity.this)) {
IsNetworkAlreadyConnected = true;
Intent timerIntent = new Intent(getBaseContext(), InActivityTimer.class);
startService(timerIntent);
}
}
and below is the code for my BroadcastReceiver in the same class,
public class mConnectivityCheckReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("android.net.conn.CONNECTIVITY_CHANGE")) {
try {
boolean networkAvailable = InternetConnectivity.isConnected(context);
if (networkAvailable) {
if (!IsNetworkAlreadyConnected) {
Intent timerIntent = new Intent(getBaseContext(), InActivityTimer.class);
startService(timerIntent);
IsNetworkAlreadyConnected = true;
}
else {
Log.d("KC_HomeActivity", "Network was already connected. No need to start service again.");
}
}
else {
Log.d("KC_HomeActivity", "Network Disconnected. Service Stopped.");
IsNetworkAlreadyConnected = false;
Intent timerIntent = new Intent(getBaseContext(), InActivityTimer.class);
stopService(timerIntent);
}
}
catch (Exception e) {
}
}
}
};
When both Mobile data and Wifi are turned on then the service is started from onCreate method and it is not started again in the BroadcastReceiver but when I turn off the Wifi the Android changes the network mode to Mobile Data but for few seconds there is no internet connectivity and the service is stopped and then started again. I don't want to do this. If there is no connectivity only then the service should be stopped. If the network is shifting from Wifi to Mobile Data then the service should not be stopped.
Note: To check the internet connectivity I am using,
NetworkInfo info = InternetConnectivity.getNetworkInfo(context);
return (info != null && info.isConnectedOrConnecting());
Network connections aren't that precise. You should make it relax a bit, or you'll pull your hair out.
I would implement a smoothing function from the broadcasts. When you get a connectivity change notification, set a timeout for like 15 seconds. At that time, check your status and either start, stop, or do nothing. If another broadcast comes in, clear the first and reset for another 15 seconds. That will give the device time to reconnect.
I've seen a couple of BroadcastReciever examples to detect wifi disconnects but none of them seem to work correctly (triggering twice for each disconnect for example) and none mention checking against an ssid, is this even possible?
So just to clarify, I want to detect disconnection from a particular ssid. An actual disconnect and not wifi being disabled on the device.
Thanks
EDIT: Re-opening as nothing works on both the devices we have to test.
NETWORK_STATE_CHANGED_ACTION was the answer in the end. The device having the problem registering this event started working when another app (which would also be listening for similar events) was uninstalled! No idea how or why an app could block events registering with another app. The final solution ended up being;
String action = intent.getAction();
if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION))
{
WifiManager manager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
NetworkInfo networkInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
NetworkInfo.State state = networkInfo.getState();
if(state == NetworkInfo.State.CONNECTED)
{
String connectingToSsid = manager.getConnectionInfo().getSSID().replace("\"", "");
WifiStateHistory.recordConnectedSsid(connectingToSsid);
//connected
}
if(state == NetworkInfo.State.DISCONNECTED)
{
if(manager.isWifiEnabled())
{
String disconnectedFromSsid = WifiStateHistory.getLastConnectedSsid();
//disconnected
}
}
}
Are you sure there are twice notification for same state? There are always two phase of disconnection:
WifiManager.WIFI_STATE_DISABLING
WifiManager.WIFI_STATE_DISABLED
My code to detect (and rebroadcast) connections and disconnects (not by disabling wifi) and including the SSID as an extra is as follows. Most of what I've read suggested using SUPPLICANT_CONNECTION_CHANGE_ACTION but this just did not work correctly, it would seemingly only fire when disabling/enabling wifi on my device (Nexus 4) and not during connections. The only problem is on first run of the app as it won't record the current ssid so doesn't know what the ssid of the network that has just been connected. Any ideas around this?
public class EventMapper extends BroadcastReceiver
{
private static String lastConnectedSsid = "";
#Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION))
{
SupplicantState state = intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE);
if(state == SupplicantState.COMPLETED)
{
WifiManager manager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
lastConnectedSsid = manager.getConnectionInfo().getSSID().replace("\"", "");
Intent newIntent = new Intent();
newIntent.setAction(Event.App_Event_WifiConnected.name());
newIntent.putExtra("App_Events_SSID", lastConnectedSsid);
context.sendBroadcast(newIntent);
}
if(state == SupplicantState.DISCONNECTED)
{
boolean wifiEnabled = ((WifiManager)context.getSystemService(Context.WIFI_SERVICE)).isWifiEnabled();
if(wifiEnabled)
{
Intent newIntent = new Intent();
newIntent.setAction(Event.App_Event_WifiDisconnected.name());
newIntent.putExtra("App_Events_SSID", lastConnectedSsid);
context.sendBroadcast(newIntent);
}
}
}
}
}
I got the same problem in some custom roms. I used "android.net.wifi.STATE_CHANGE" to listen the network change. In the receiver, I used "(NetworkInfo)intent.getParcelableExtra("networkInfo")).getState()" to get the network state. There are three states: DISCONNECTED, CONNECTING, CONNECTED. You can use DISCONNECTED to detect if the network is disconnected.
Please let me know if it works in your situation(HTC One X (4.1)).
Well, I want to check the version of a site (this part I know how) every 6h or so.
So, I was thinking about making a service for this and use AlarmManager for it.
Since I need Internet to check the version of the site, I need something to see if the internet is on or to see when it's turned on. After the time passed I'll
So my questions (yep, not just one!) are:
Does AlarmManager works even if the display goes to sleep? When the device wakes up it knows how many time as passed and if passed more that 6h it executes the task?
How to check when internet is available?
How to know when internet is turned on? (some kind of broadcast?)
Is this a good solution?
Alarm Manager:
The alarm manager does not have anything to do with the display state, so Yes it can work even if the screen is off.
Network Avaiability snippet:
public boolean isNetworkAvailable() {
Context context = getApplicationContext();
ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity == null) {
boitealerte(this.getString(R.string.alert),"getSystemService rend null");
} else {
NetworkInfo[] info = connectivity.getAllNetworkInfo();
if (info != null) {
for (int i = 0; i < info.length; i++) {
if (info[i].getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
}
}
return false;
}
This function will return true if the network is available, false if it is not (airplane mode, out of reach, etc.)
Don't forget to add permission in your manifest
A possible solution
Have broadcast receiver for the screen off & screen on events like below,
public class ScreenReceiver extends BroadcastReceiver {
public static boolean wasScreenOn = true;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
// do whatever you need to do here
wasScreenOn = false;
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
// and do whatever you need to do here
wasScreenOn = true;
}
}
}
In this receiver give the logic for requesting if network is available..
About the alarm manager. Here is a possible code:
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC, System.currentTimeMillis() + 10000, 6*60*60*1000, pendingIntent);
The first parameter influence how device behave:
RTC - alarm does not wake the device up; if it goes off while the device is asleep, it will not be delivered until the next time the device wakes up
RTC_WAKEUP - wake up the device when it goes off
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);
}
}
}