I've write a code for launch a service each half hour when my app is closed:
Intent serviceIntent = new Intent(context, BackgroundService.class);
pIntent = PendingIntent.getService(context, 0, serviceIntent, 0);
alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
AlarmManager.INTERVAL_HALF_HOUR, AlarmManager.INTERVAL_HALF_HOUR, pIntent);
Where BackGround service extends IntentService, download some data from a server, and if some conditions are verifyed, show a notification on notification bar.
But it happen that service is executed immediatly when i close my app, and not after half hour.
How can i correct my code for make first execution after half hour?
But it happen that service is executed immediatly when i close my app, and not after half hour.
The second parameter to setInexactRepeating() is when you want the event to first occur. When using ELAPSED_REALTIME or ELAPSED_REALTIME_WAKEUP, that needs to be expressed as SystemClock.elapsedRealtime()+..., where ... is how far from now (SystemClock.elapsedRealtime()) you want the event to occur in milliseconds. Your code does not do this; your desired start time is in the past.
Related
I'm developing an app which you can schedule your time and It reminds you on time just like google calendar. I use AlarmManager class and set a Repeating task to check Database every one minute and see if there is any alarm on that time or not.
#Override
public void onReceive(Context context, Intent intent) {
Calendar now = Calendar.getInstance();
doRepeatingWorks(now.getTimeInMillis()); // Like Checking if one day passed to do some tasks
checkDbIfThereIsSomeSchedule(now);
}
And I call this to start alarm manager:
public void setAlarm(Context context) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), G.ALARM_CHECK_INTERVAL_MILIS, pendingIntent);
}
But it's inaccurate and sometimes I figure out that the task killer apps kill my alarm and make it totally worthless.
Although using a foregroundService is battery consuming and it goes on user's nerve with the notification.
Is there any solutions or alternatives for this problem?
I use AlarmManager class and set a Repeating task to check Database every one minute and see if there is any alarm on that time or not
That is a truly awful approach. This sort of behavior is precisely why Doze mode and app standby were added in Android 6.0.
Is there any solutions or alternatives for this problem?"
Schedule an alarm event for first event. When you get control, notify the user about the event, then schedule an alarm event for the next event in sequence. If the user adds a new event that is sooner than your first event, cancel the previous alarm and schedule one for the new first event.
You don't need to check there is an alarm in each 1 min. I hope this post helps you - Scheduled Alarm Manager not working Android
I let my background service send the geo data of the device to an API.
private static long LOCATION_INTERVAL = 1800000;
Is supposed to be the interval for the location service and the AlarmManager.
The first alarm I fire in MainActivity like this
Intent i = new Intent(this, typeof(LocationService));
PendingIntent pending = PendingIntent.GetService(this, 1, i,
PendingIntentFlags.CancelCurrent);
AlarmManager alarm = (AlarmManager)GetSystemService(AlarmService);
alarm.SetExact(AlarmType.RtcWakeup, 30000, pending);
Then, in the Service itself, I re-trigger the alarm all the time like this
Intent intent = new Intent(this, typeof(LocationService));
PendingIntent pending = PendingIntent.GetService(this, 100, intent,
PendingIntentFlags.CancelCurrent);
AlarmManager alarm = (AlarmManager)GetSystemService(AlarmService);
alarm.SetExact(AlarmType.RtcWakeup,
LOCATION_INTERVAL, pending);
Problem: The service gets called way too soon (+/- every minute!).
Question: How can I make my alarm manager stick to LOCATION_INTERVAL?
Could you please check the solution below and let me know the results?
If does not work, I delete the answer....
ISSUE
I believe the error is here:
alarm.SetExact(int type, long triggerAtMillis, PendingIntent operation);
triggerAtMillis: time in milliseconds that the alarm should go off, using the appropriate clock (depending on the alarm type).
So, your are using 1800000 as triggerAtMillis. However, 1800000 is following date in UTC: Thu Jan 01 1970 00:30:00
Since this is an old date, the alarm is fired immediately.
Solution
Maybe, you should update your code as follows:
In MainActivity, I believe that you want to fire the alarm immediately. So, create it as follows:
alarm.SetExact(AlarmType.RtcWakeup, Calendar.getInstance().getTimeInMillis(), pending);
In your service, it seems that you want to trigger your alarm after 1800000. So, you have to use:
alarm.SetExact(AlarmType.RtcWakeup, Calendar.getInstance().getTimeInMillis() + LOCATION_INTERVAL, pending);
This way, alarm will be fired 30 minutes after current time (current time + LOCATION_INTERVAL).
Keep in mind that second parameter is the date in milliseconds... It is a number which represents an whole date (and not only an interval)...
I'm building a reminders application where one time, weekly, monthly reminders and we notify the user of the reminder on due date and time. Reminders can be updated any time by the user to update the reminding time or delete the reminder altogether. I have thought of two ways I can solve the particular problem.
Whenever user sets a reminder, schedule an alarm accordingly with an unique Id and update or delete it in case user updates or deletes the alarm.
Since I store the reminding time in DB, better approach would be to schedule an alarm for the nearest reminder. And have the Service which is triggered by the alarm schedule a new alarm for the next nearest reminder.
2nd approach seems clean approach but how do we tackle the case where the Service triggered by alarm gets killed by the system before it schedules a new alarm for the next reminder?
Edit
Looks like if the system kills a Service for memory, it will re-create the Service. Does it mean it is safe to rely on the Service to schedule alarm every time it is run?
Edit 2
I've realized that Android kills any alarms whenever the device is restarted. This makes approach 2 a better solution. I've implemented it for now.
The pending intent needs to be created exactly in the same way for canceling the already set alarm. You can cancel previous alarm when you set a new alarm, if you want to have a single alarm activated at some time.
For setting alarm use:
Intent myIntent = new Intent(getApplicationContext(), SessionReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 1, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, now.getTimeInMillis(), pendingIntent);
For canceling the alarm use:
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent myIntent = new Intent(getApplicationContext(), SessionReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 1, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.cancel(pendingIntent);
I'm usign an Alarm Manager to update a widget with a Service. I've two different questions.
First question: I'm calling the service with Alarm Manager's intent. Like this:
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, MyService.class);
pi = PendingIntent.getService(context, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
context.startService(new Intent(context, MyService.class));
Long repeat = Long.parseLong(prefs.getString("update_preference", "600"));
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis(), 1000*repeat, pi);
Is it wrong?
It looks and works right. But when I have looked at working services, I can't see my service name in the list. Perhaps it's not running as a single/seperate service. Just saw application name (not as a service). I'm not sure how to seperate or does it matter?
Another question: Over long time, running application, which controls widgets update, is closed somehow (manually or by a task killer). Of course Alarm Manager gonna stop and widget's functions gonna stop too. For example button clicking.
But, Twitter solved this problem. While the widget is active, if I close the main application (Twitter) -which controls widget- than click the widget, somehow widget triggering application and it starts again well. So buttons work properly. How is that possible?
Any help would be appreciated.
You dont need to do context.startservice that what the pending intent is for, if you want the service to run right away the first time just set it to run at the current time then set the interval from the current time.
You are also setting 2 different types of repeating when you don't need to setRepeating is strict where setInexact is not and can be adjusted by the OS when it gets fired hence the inexact in it. You want one or the other not both.
Also those intervals are very small and its going to kill the battery significantly.
It should just be this
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, MyService.class);
pi = PendingIntent.getService(context, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
Long repeat = Long.parseLong(prefs.getString("update_preference", "600"));
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP,
Calendar.getInstance().getTimeInMillis(), 1000*repeat, pi);
It's good that your application/service isn't running all the time.
In fact it doesn't need/has to run all the time for updating a widget. If you schedule an Intent with AlarmManager the application will be started when the intent is fired if it has been closed.
This works fine:
Intent intent = new Intent(HelloAndroid2.this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(HelloAndroid2.this, 0,
intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (12 * 1000), pendingIntent);
This doesn't work. I hear the alarm only time.
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (12 * 1000), 3 * 1000, pendingIntent);
I have also tried this, no luck:
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 5);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 7000, pendingIntent);
What is the problem?
From the PendingIntent doc for FLAG_ONE_SHOT:
this PendingIntent can
only be used once. If set, after
send() is called on it, it will be
automatically canceled for you and any
future attempt to send through it will
fail.
So after the pendingIntent is fired the first time, it will be cancelled and the next attempt to send it via the alarm manager will fail
Try using FLAG_UPDATE_CURRENT
Looking at your code samples in order:
In your first sample you are using AlarmManager.set - this is strictly for one-off alarms so yes, it will only fire once. If you want to use AlarmManager.set then the last thing the code triggered should do is to set a fresh alarm (which should also use a fresh PendingIntent).
In your second example you are using a repeating alarm. You do not need to create a fresh PendingIntent each time this fires as the OS takes care of the repeating aspect of the alarm.
There is no reason why your alarm should not repeat every 3 seconds, so I would start looking at the BroadcastReceiver implementation you have written to handle the alarm.
Check that you've implemented it properly. Comment out all the code in the onReceive() method and instead just have it writing a log message. Once you see your log message appearing in the logcat every time the alarm fires, add your code back in (keeping the log message), and another log message to the end of the method. This allows you to see how long the method takes to execute - you want it to be finished before the alarm fires again to avoid any unexpected side effects.
As an aside, if you want a repeating alarm, android.os.Handler is a much more efficient approach although alarms set through AlarmManager do fire very accurately.