I have a very simple alarm manager to do things while the device is awake. So I figured AlarmManager.RTC was my best approach. As according to AlarmManager API the device is supposed to ignore the next occurring alarm until the device wakes up, then will it send its pending intent instructions.
Here is the code that I have scheduling the Alarm:
Intent intent = new Intent(getApplicationContext(), WorkerService.class);
PendingIntent pIntent = PendingIntent.getService(getApplicationContext(), 0, intent, 0);
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC, System.currentTimeMillis(), 10000, pIntent);
And here is the code inside the "WorkerService.class"
public void onCreate() {
super.onCreate();
stopSelf();
}
public void onDestroy() {
super.onDestroy();
Log.i("Service Status", "Service exited");
}
What am i doing wrong here?
Now I know I can write a screen receiver, but then I would have to have another service open to hold that receiver (kinda annoying) when alarm manager is supposed to be ignoring my alarm when the screen is off.
I used Log.i to inform me if the service ran. I was able to tell in eclipse's logcat what the output was by using ADB Over WiFi this way the device was allowed to sleep.
Thanks guys, im truly stumped.
Related
I have a situation in my application. I am calling a service using an alarm. The alarm wakes up every 5 min and calls the service.
But it may so happen that the user might close my app and I am allowing the functionality of the service to work even if the user is not using my app.
To stop the service there are two ways either the user comes back to the app and presses a button which will cancel the alarm OR the second way is say after x time I want to stop the service i.e cancel the alarm from a broadcast receiver.
Now how can I do the second way ? When I tried to get reference of the AlarmManager it is giving me error of Null Pointer. (I am accessing this alarm manager from a broadcast receiver)
Can anyone give me suggestion on how to cancel repeating alarms from outside the activity context ?
Thanks :)
You can stop your service like this
context.stopService(new Intent(context, YourService.class))
Also in order to cancel the alarm you can do this
Intent intent = new Intent(this, YourClass.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 1253, intent, PendingIntent.FLAG_UPDATE_CURRENT| Intent.FILL_IN_DATA);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
I hope this might help you
In your BroadcastReceiver try this:
public void onReceive(Context context, Intent intent) {
context.stopService(new Intent(context, YourService.class));
}
I've set a repeating alarm on a service and decided that it's most convenient to reset the alarm from within the called service. The reason is that the service already has code to check if it's within a user-defined schedule (time range). When it's outside the time range, it resets the alarm to start at the future time selected by the user. Maybe I'm approaching this wrong but I'll put this question out there and see what you think.
An activity kicks off the service by creating a repeating alarm:
//Activity
Calendar cal = Calendar.getInstance();
Intent intent = new Intent(getApplicationContext(), MyService.class);
intent.setData(Uri.parse("MyService://identifier"));
PendingIntent pIntent = PendingIntent.getService(getApplicationContext(), 0, intent, 0);
AlarmManager alarm = (AlarmManager)getSystemService(ALARM_SERVICE);
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
intervalInMins*60000, pIntent);
The service has something like this:
//Service
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Uri Action = intent.getData();
try {
if (Action.equals(Uri.parse("MyService://identifier"))) {
//Simplifying the code here: CalculatedOffset is determined from the current time
//and scheduled start time. intervalInMins is read from settings.
if (!WithinSchedule()) {
Calendar cal = Calendar.getInstance();
PendingIntent pIntent = PendingIntent.getService(getApplicationContext(), 0, intent, 0);
AlarmManager alarm = (AlarmManager)getSystemService(ALARM_SERVICE);
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis() + CalculatedOffset,
intervalInMins*60000, pIntent);
}
}
} catch (NullPointerException np) {
np.printStackTrace();
}
return Service.START_REDELIVER_INTENT;
}
I was hoping to re-use the intent to reset the repeating alarm. With this new code, I'm seeing multiple alarms stack up firing rapidly in succession around when the start time hits. It should not spaz out like that, but should fire at regular intervals as it did before the scheduling reset. I need to catch it in the debugger but haven't been able to determine the exact conditions yet. Is my understanding of alarms completely off base here? Is there a better way to do this?
Addendum: A wrinkle in this is that I'm using RootTools to gain superuser privileges in order to work around Android 4.2's airplane mode. This hasn't been a problem before the scheduling, but I'm suspicious whether su is blocking for a long time while the alarms stack up.
Re-using the intent inside the service that receives the alarm does work. I've switched from using a Repeating Alarm to a single-shot alarm which gets re-armed every time the service is called. Unfortunately this didn't fix the problem of the alarms stacking. The culprit is definitely su blocking. It may be RootTools or su itself. I need to update the library from 2.6 to 3.x and see if that makes any difference.
I have created an On Boot Receiver to repeatedly call a wakeful intent service every 5 minutes but cannot figure out how to start the service immediately when the app is installed..? I do not want to rely on the user rebooting their device before it starts to run!
Here is my code so far :
public class OnBootReceiver extends BroadcastReceiver {
private static final int PERIOD = 300000; // check every 5 minutes
#Override
public void onReceive(Context context, Intent intent) {
AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, OnAlarmReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
mgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 60000, PERIOD, pi);
}}
Can anyone help me out pls? :)
If you want to set an alarmmanager to start your service when the app is installed, then it's not possible. It's a OS limitation, security if you will. But if you want to start the service in the moment the app starts, just call it, it will keep runing.
Essentially, since the Application object is created when the application is started and when the BOOT_COMPLETED Intent is received, you could register with the AlarmManager in the onCreate method in your custom Application class. Just be aware that the Application object is instantiated every time the process starts, which includes cases where the process is temporarily killed to save resources. But if you don't change the PendingIntent in any way, it should be no problem to register over and over again.
However, it is not possible to start the application when it is installed, there has to be some user interaction first.
I have an application that does some data processing, then notifies the user in the status bar if any new items are found. The process runs as an AlarmManager at a set amount of time. Everything works fine, but I'd ideally not like the user to be notified while they are actively using the application, which means the AlarmManager should basically be suspended. The only solution I could think of is constantly start/stop the alarm in the main Activity's onResume method similar to this:
#Override
public void onResume()
{
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
Intent myIntent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, myIntent, 0);
alarmManager.cancel(pendingIntent);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 600000, 600000, pendingIntent);
}
This isn't foolproof, but the best solution I could think of. Just wondering if that is bad practice or if there is a better solution? Thanks.
Just have your AlarmReceiver (or the Service it invokes) check to see if the app is visible or not. You need to share some state between your app and the AlarmReceiver/Service. You could have a base Activity that tells your AlarmReceiver/Service that is in the foreground during onResume and that it is in the background during onPause. Then the AlarmReceiver/Service can simply check this state when the alarm goes off and use that to decide if a notification should be shown or not.
My application have a Service that every X minutes do same action on the database than it stopSelf() and into onDestroy method I have palced this code for restart the service after same time:
#Override
public void onDestroy() {
super.onDestroy();
Intent intent_service = new Intent(context,vampireService.class);
PendingIntent pintent = PendingIntent.getService(context, 0, intent_service,0);
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarm.set(AlarmManager.ELAPSED_REALTIME,SystemClock.elapsedRealtime()+ 4500000, pintent);
}
But I don't understand why if my phone go in sleep mode the service not restart ! Appears that the count time of AlarmManager to start when I power back up the display....it's possibile ? If yes, how can I resolve this problem ?
Thanks
From the documentation for ELAPSED_REALTIME...
This 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.
Try using ELAPSED_REALTIME_WAKEUP to see if that helps (not sure if it will work for a service however).
You can (and should) schedule your Service to run every X time, using the Alarm Manager. You have this option of setRepeating.