I have a service which polls a server at certain intervals. I use an AlarmManager and a BroadcastReceiver to start the service. My problem is that after a certain duration, even though the Wifi is still enabled, but for some reason, my application can't contact the server. I get an "Unreachable network" error.
Note that I've already acquired a partial wake lock as well as a wifilock.
Here's my code for the BroadcastReceiver.
public class ServiceAlarmBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
WakeLock wakeLock = null;
WifiLock wifiLock = null;
try {
PowerManager pm = (PowerManager) context
.getSystemService(Context.POWER_SERVICE);
// acquire a WakeLock to keep the CPU running
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"MyWakeLock");
if(!wakeLock.isHeld()){
wakeLock.acquire();
}
Log.i("ServiceAlarmBroadcastReceiver", "WakeLock acquired!");
WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
wifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL , "MyWifiLock");
if(!wifiLock.isHeld()){
wifiLock.acquire();
}
Log.i("ServiceAlarmBroadcastReceiver", "WifiLock acquired!");
context.startService(new Intent(context, ThePollerService.class));
} finally {
// release the WakeLock to allow CPU to sleep
if (wakeLock != null) {
if (wakeLock.isHeld()) {
wakeLock.release();
Log.i("ServiceAlarmBroadcastReceiver", "WakeLock released!");
}
}
// release the WifiLock
if (wifiLock != null) {
if (wifiLock.isHeld()) {
wifiLock.release();
Log.i("ServiceAlarmBroadcastReceiver", "WiFi Lock released!");
}
}
}
}
}
The problem with the code posted here is that you acquire and release the WakeLock and WifiLock from right inside of your receiver. Unless you are completing your entire task inside of the onStart of your service (which if you are, why even bother having a service???), the locks will be released before your polling task completes.
I would suggest changing your implementation to something like the following:
Have broadcast receiver start service (and that is all)
Have service acquire wake locks and kick off the thread to do your polling operation. The most appropriate spot would be your service onCreate)
After your polled operation is complete, you should stop your polling service
In the onDestroy of your service, you should release the locks you acquired in onStart
Thanks to Tom, I was able to resolve this issue. Here's the code:
Settings.System.putInt(getContentResolver(),
Settings.System.WIFI_SLEEP_POLICY,
Settings.System.WIFI_SLEEP_POLICY_NEVER);
Under the WiFi Settings, Menu Key, Advanced Options theirs the WIFI_SLEEP_POLICY option list which when set to never will keep the WiFi connection open while the phone is asleep.
You can manipulate this under Settings.System Package.
http://developer.android.com/reference/android/provider/Settings.System.html#WIFI_SLEEP_POLICY
Hope this helps,
Tom
A little edit to javauser's answer:
private void setNeverSleepPolicy() {
try {
ContentResolver cr = getContentResolver();
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) {
int set = android.provider.Settings.System.WIFI_SLEEP_POLICY_NEVER;
android.provider.Settings.System.putInt(cr, android.provider.Settings.System.WIFI_SLEEP_POLICY, set);
} else {
int set = android.provider.Settings.Global.WIFI_SLEEP_POLICY_NEVER;
android.provider.Settings.System.putInt(cr, android.provider.Settings.Global.WIFI_SLEEP_POLICY, set);
}
} catch (Exception e) {
e.printStackTrace();
}
}
Related
I am calling a service from an AlarmManager onReceive, below is the implementation. I want to know if this implementation of a wake lock is fine and will it suffice my needs?
This is the onStart function in my Service Class:
#Override
public void onStart(Intent intent, int startId) {
WakeLock wakeLock = null;
try{
PowerManager mgr = (PowerManager)getApplicationContext()
.getSystemService(Context.POWER_SERVICE);
wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
wakeLock.acquire();
//For time consuming an long tasks you can launch a new thread here
Toast.makeText(this, " Service Started", Toast.LENGTH_LONG).show();
}catch(Exception e){
}finally{
wakeLock.release();
}
}
Yep, that should work fine. Although it won't work if you spin up a new Thread, in that case wakelock.release() will be called before the Thread finishes.
You might want to check CommonsWare's Wakeful service though. That services handles the wakelock for you, ensuring that you have a Wakelock during the service, and it'll release it as soon as you stop the service.
i have a chat application.my code has a thread which manages internet connection.
but after some minutes my thread goes sleep.
I know i should use WakeLock to wake CPU and my thread.
but when i use below code , battery usage goes up.
if (mWakeLock == null) {
mWakeLock = pm.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK,
"NewOnlineSignalingPowerManagerTag");
}
if (mWifiLock == null) {
mWifiLock = wm.createWifiLock(
WifiManager.WIFI_MODE_FULL,
"NewOnlineSignalingWifiManagerTag");
}
if (!mWakeLock.isHeld()) {
logging.l("mWakeLock.acquire()");
mWakeLock.acquire();
}
if (!mWifiLock.isHeld()) {
logging.l("mWifiLock.acquire()");
mWifiLock.acquire();
}
can you prefer me a better way?
Why do you have to manage a internet connection? You don't have to. Use a Android service, and there won't be a thread issue, nor a sleep issue.
I'm building a simple app that has BroadcastReciever that listens to PHONE_STATE:
<receiver android:name=".PhoneStateBroadcastReceiver" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
In the BroadcastReciever's onRecieve() I start a service when the state is OFFHOOK and stop the service when the state is IDLE:
public class PhoneStateBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
String state = bundle.getString(TelephonyManager.EXTRA_STATE);
if(state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
context.startService(new Intent(context, ProximityService.class));
}
else if(state.equals(TelephonyManager.EXTRA_STATE_IDLE)){
context.stopService(new Intent(context, ProximityService.class));
}
}
}
In the service I'm registering proximity sensor listener, and creating a WakeLock so the screen will turn off well while on call.
After the call ends I stop the service, and in its onDestroy() I'm unregistering the listener and release the WakeLock.
But it seems that something is not releasing out there because I see a huge battery drain from my app (30%).
I put a Log when the listener unregistering and also on the WakeLock release, and I can see that the WakeLock is released and the listener is unregistered successfully (I can also see the Log from SensorManager that the listener is unregistered).
What am I missing here?
That's really annoying.
Some code of the service:
public int onStartCommand(Intent intent, int flags, int startId){
Log.d("CALL", "Service started");
// Get an instance of the sensor service, and use that to get an instance of
// a particular sensor.
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mProximity = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
mSensorManager.registerListener(this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
mAudioManager = (AudioManager)this.getSystemService(Context.AUDIO_SERVICE);
mPowerMngr = (PowerManager) getSystemService(Context.POWER_SERVICE);
try{
mWakeLock = mPowerMngr.newWakeLock(PROXIMITY_SCREEN_OFF_WAKE_LOCK, "Proximity");
if (!mWakeLock.isHeld()) {
Log.d("CALL", "Wake lock acquired");
mWakeLock.acquire();
}
}
catch (Exception e){
mWakeLock = null;
}
return START_STICKY;
}
public void onDestroy(){
super.onDestroy();
mSensorManager.unregisterListener(this);
if (mWakeLock != null) {
if (mWakeLock.isHeld()) {
Log.d("CALL", "Wake lock released");
mWakeLock.release();
}
}
Log.d("CALL", "Service stopped");
}
The log I see:
09-30 03:35:09.120: D/SensorManager(21565): unregisterListener:: disable all sensors for this listener, listener = com.eladaharon.android.proximity.ProximityService#41a31a18
09-30 03:35:09.125: D/CALL(21565): Wake lock released
09-30 03:35:09.125: D/CALL(21565): Service stopped
Thanks a lot!
Elad
If your service is receiving multiple intents, your code will create a new WakeLock each time onStartCommand is executed. You would be releasing only the last WakeLock and leaking the others, which would explain the battery drain. Logcat will normally provide helpful messages in this situation.
Since your service remains running for a time, you could check whether mWakeLock is initialized before calling newWakeLock().
I have a service which polls a server at certain intervals. I use an AlarmManager and a BroadcastReceiver to start the service. My problem is that after a certain duration, even though the Wifi is still enabled, but for some reason, my application can't contact the server. I get an "Unreachable network" error.
Note that I've already acquired a partial wake lock as well as a wifilock.
Here's my code for the BroadcastReceiver.
public class ServiceAlarmBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
WakeLock wakeLock = null;
WifiLock wifiLock = null;
try {
PowerManager pm = (PowerManager) context
.getSystemService(Context.POWER_SERVICE);
// acquire a WakeLock to keep the CPU running
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"MyWakeLock");
if(!wakeLock.isHeld()){
wakeLock.acquire();
}
Log.i("ServiceAlarmBroadcastReceiver", "WakeLock acquired!");
WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
wifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL , "MyWifiLock");
if(!wifiLock.isHeld()){
wifiLock.acquire();
}
Log.i("ServiceAlarmBroadcastReceiver", "WifiLock acquired!");
context.startService(new Intent(context, ThePollerService.class));
} finally {
// release the WakeLock to allow CPU to sleep
if (wakeLock != null) {
if (wakeLock.isHeld()) {
wakeLock.release();
Log.i("ServiceAlarmBroadcastReceiver", "WakeLock released!");
}
}
// release the WifiLock
if (wifiLock != null) {
if (wifiLock.isHeld()) {
wifiLock.release();
Log.i("ServiceAlarmBroadcastReceiver", "WiFi Lock released!");
}
}
}
}
}
The problem with the code posted here is that you acquire and release the WakeLock and WifiLock from right inside of your receiver. Unless you are completing your entire task inside of the onStart of your service (which if you are, why even bother having a service???), the locks will be released before your polling task completes.
I would suggest changing your implementation to something like the following:
Have broadcast receiver start service (and that is all)
Have service acquire wake locks and kick off the thread to do your polling operation. The most appropriate spot would be your service onCreate)
After your polled operation is complete, you should stop your polling service
In the onDestroy of your service, you should release the locks you acquired in onStart
Thanks to Tom, I was able to resolve this issue. Here's the code:
Settings.System.putInt(getContentResolver(),
Settings.System.WIFI_SLEEP_POLICY,
Settings.System.WIFI_SLEEP_POLICY_NEVER);
Under the WiFi Settings, Menu Key, Advanced Options theirs the WIFI_SLEEP_POLICY option list which when set to never will keep the WiFi connection open while the phone is asleep.
You can manipulate this under Settings.System Package.
http://developer.android.com/reference/android/provider/Settings.System.html#WIFI_SLEEP_POLICY
Hope this helps,
Tom
A little edit to javauser's answer:
private void setNeverSleepPolicy() {
try {
ContentResolver cr = getContentResolver();
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) {
int set = android.provider.Settings.System.WIFI_SLEEP_POLICY_NEVER;
android.provider.Settings.System.putInt(cr, android.provider.Settings.System.WIFI_SLEEP_POLICY, set);
} else {
int set = android.provider.Settings.Global.WIFI_SLEEP_POLICY_NEVER;
android.provider.Settings.System.putInt(cr, android.provider.Settings.Global.WIFI_SLEEP_POLICY, set);
}
} catch (Exception e) {
e.printStackTrace();
}
}
im receiving an intent in broadcast receiver and then i start service to do more work. now what if the device is sleep and this happen, do i have to get Wakelock (AlarmManger?), and why do i need it?
does my service will stop running if the device goes to sleep without getting a wakelock.
now what if the device is sleep and this happen, do i have to get Wakelock (AlarmManger?), and why do i need it?
If the device is asleep to begin with, you will not be "receiving an intent in broadcast receiver", because the device is asleep.
do i have to get Wakelock (AlarmManger?), and why do i need it?
You don't "need it", unless you want to ensure the device stays running while you complete some work.
does my service will stop running if the device goes to sleep without getting a wakelock.
Yes.
Looks like the Android's native WakefulBroadcastReceiver would be a perfect solution for you. Need to extend this rather than the regular BroadcastReceiver and start the service in the onReceive() in the "wakeful" manner:
startWakefulService(context, service);
and signal your work is done in the service's onHandleIntent(), calling
MyWakefulReceiver.completeWakefulIntent(intent);
public class WakeLockManager extends BroadcastReceiver {
private static WakeLock mWakeLock;
private String LCLT;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Consts.WAKELOCK_INTENT)) {
Log.v("wakelock", "GOT THE wakelock INTENT");
boolean on = intent.getExtras().getBoolean("on");
if (mWakeLock == null) {
PowerManager pm = (PowerManager) context
.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"Breeze WakeLock");
}
if (on) {
if (!mWakeLock.isHeld()) {
mWakeLock.acquire();
Log.v("wakelock", "acquiring wakelock");
}
} else {
if (mWakeLock.isHeld()) {
Log.v("wakelock", "releasing wakelock");
mWakeLock.release();
}
mWakeLock = null;
}
}
}
}
look at the above code ..put it in a separate class file and and in your manifest define it for some custom intent .... now that this class will respond to a custom intent ...just broadcast that intent and you can turn the wakelock on or off in your entire app since the wakelock is static..like this :
public void setWakeup(boolean status) {
Intent wakelock_Intent = new Intent(CUSTOM_INTENT);
wakelock_Intent.putExtra("on", status);
this.sendBroadcast(wakelock_Intent);
}
the above would be defined in your alarmmanager code so it schedules a call