Starting a service at a specific time every day - java

i made a calendar to show toast in specific time every day at 8:00 pm
but the app show start the service and show the toast in different time.
like
8:00 pm
8:23 pm
8:30 pm
8:32 pm
8:50 pm
and doesn't stop showing the toast
what is the wrong?
this is my Mainactivity.java code
Intent alarmIntent = new Intent(MainActivity.this, MyService.class);
pendingIntent = PendingIntent.getService(MainActivity.this, 0, alarmIntent, 0);
setAlarm();
}
private void setAlarm() {
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
/* Set the alarm to start at 8.00 PM */
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 20);
calendar.set(Calendar.MINUTE, 00);
calendar.set(Calendar.SECOND, 00);
//Add a day if alarm is set for before current time, so the alarm is triggered the next day
if (calendar.before(Calendar.getInstance())) {
calendar.add(Calendar.DAY_OF_MONTH, 1);
}
manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS), pendingIntent);
}}

From the documentation of setRepeating
Note: as of API 19, all repeating alarms are inexact. If your application needs precise delivery times then it must use one-time exact alarms, rescheduling each time as described above. Legacy applications whose targetSdkVersion is earlier than API 19 will continue to have all of their alarms, including repeating alarms, treated as exact.
EDIT
You alarm being inexact, it means that the system will not wake up in the exact time you set 00:800 to fulfill your request, instead it will group some actions that needs to be done, somewhere around the time you set, and fire them all together to save battery of the phone, and do prevent the phone from being awake every couple of seconds separately.
You can replace your call to non repeating call using AlarmManager.set() and handling repetition yourself, as in each alarm firing schedules the next one.
Or if your alarm firing is not time critical (it doesn't not have to be very exact), you can leave it as it is.

To have a precise alarm instead of using setRepeating use setAndAllowWhileIdle
otherwise, if you are not in need of precise timing I would recommend you to use firebase job dispatcher to schedule your job https://github.com/firebase/firebase-jobdispatcher-android

Related

How to set an alarm to exact hour on following days?

I'm trying to make an alarm that besides shoot today, repeat on the exact same hour on the next day.
Not having any success until now.
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, timeHOUR);
calendar.set(Calendar.HOUR, timeHOUR);
calendar.set(Calendar.MINUTE, timeMINUTE);
The alarm must occur at the same times on the following days.
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
Also i need to be able to register more than 1 alarm. I'm not sure if setRepeating() supports that.

The AlarmManager is unreliable, are there improvements or alternatives?

I need a widget to be updated frequently using a set value, like every 1-5 seconds.
I found out that for this an AlarmManager should be used.
I tested the AlarmManager's setExact() method and found out, that its minimum time is exactly 5 seconds.
I also noticed that the interval can have huge delays.
I tested this with a set interval of 5 seconds.
My test showed for the setExact() method following values: 5s, 5s, 40s, 41s, 19s, 5s, 5s, ...
Using the setRepeating() method showed even worse value: 17s, 39s, 7s, 75s, 60s, ... Apparently the AlarmManager also does not trigger at all when used on a Samsung Device, which is the Device I am planning to use the widget on.
Is there an alternative to using an AlarmManager?
Can the AlarmManager somehow become more reliable?
I need the update rate to be constant, without delays like this.
final AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent notifyIntent = new Intent(this, AlarmReceiver.class);
final PendingIntent notifyPendingIntent = PendingIntent.getBroadcast
(this, NOTIFICATION_ID, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
long triggerTime = SystemClock.elapsedRealtime()
+ 3000;
long repeatInterval = 1000;
alarmManager.setExact(AlarmManager.RTC_WAKEUP,
triggerTime, notifyPendingIntent);
Besides the AlarmManager I have checked out the JobScheduler and Worker, but both seem to underlie a 15 minute (!) minimum interval.
Using a simple Thread seems to be working however. I just have to find out how to make it run reliably then...
If you know other solutions please let me know!

AlarmManager inconsistent behavior (alarm firing multiple times, or not at all)

I have a button that sets an Alarm using the AlarmManager.setRepeating and another button that removes it, every time an alarm is set the requestCode in the PendingIntent is iterated as to not confuse it with one that has already been set and canceled (the app will have multiple alarms set at the same time in the future). when i set the alarm (setRepeating) sometimes it works as intended sometimes it will fire off twice really quickly than at the time it was intended to go off 2-3 minutes later (i'm setting the alarm 3-5 minutes in the future for my test).
Also note: I have the device plugged in and the screen is set to stay a wake, during testing the app is usually always in foreground, sometimes i put it to background or rotate the screen (usually by mistake).
I have tried setExact() but i don't mind if its off by 0-5 minutes but i do need it to go off and not repeat.
i have played around with the initial time setting it to have started the day before at the hour and minute i want it to go off, same thing with ten days back and a hundred (just to see what would happen) similar results.
I am using Joda DateTime to get the milliseconds of the alarm time for the setRepeating method, and using AlarmManager.INTERVAL_DAY to set the intervals for the next alarm (my alarms need to go off every 24 hours)
requestCode is a constant int that i increment and track during testing.
context i get from getBaseContext() in the activity
My code to set the alarm:
Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
intent.putExtra(ALARMS_INDEX_KEY,requestCode);
PendingIntent sender = PendingIntent.getBroadcast(context, requestCode, intent, 0);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);//After after 5 seconds
addAlarmIndex(context, requestCode);
//test: DateTime.now().minusDays(10).withTimeAtStartOfDay()
DateTime set_for = DateTime.now().withTimeAtStartOfDay().withHourOfDay(14).
withMinuteOfHour(34).withSecondOfMinute(0).
withMillisOfSecond(0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, set_for.getMillis(), AlarmManager.INTERVAL_DAY , sender);
My code to cancel the alarm:
Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(context, requestCode, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
My code in AlarmManagerBroadcastReceiver extends BroadcastReceiver
#Override
public void onReceive(Context context, Intent intent) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "test_alarm:");
wl.acquire();
int alarm_index = -1;
if(intent.hasExtra(ALARMS_INDEX_KEY)){
alarm_index = intent.getIntExtra(ALARMS_INDEX_KEY,-1);
}
Log.i("medic_debug_timertest","Alarm !!!, fired #: "+DateTime.now().toString("YYYY/MM/dd # HH:mm:ss") + " alarm_index: " + requestCode);
wl.release();
}
What i'm expecting is the alarm gets set before the time it is meant to go off, than the alarm going off at the time it was set to go off at (withing several minutes of that time)
what happens is sometimes it dose not go off at all (perhaps I set the alarm to go off to close to when i am setting it) this may not be a problem but other times it goes off shortly after i set it and it will go off twice within 0-1 seconds apart that 1-2 minutes later it will go off again at the correct time it was set to go off at.
from what i observed so far it is always one of the three scenarios:
goes off at the correct time.
goes off not at all.
goes off three times, twice right away (1-2 minutes before the scheduled time) and than a third time at the correct time.
What am i doing wrong? how can I get the alarm to go off once at approximately the right time
UPDATE:
ok so... first of all I changed changed the line that sets up the timer from:
DateTime set_for = DateTime.now().minusDays(10).withTimeAtStartOfDay().withHourOfDay(14).
withMinuteOfHour(34).withSecondOfMinute(0).
withMillisOfSecond(0);
to
DateTime set_for = DateTime.now().plusMinutes(5).withSecondOfMinute(0).withMillisOfSecond(0);
so that it will go off exactly 5 minutes from when i set it and i can make multiple test without re running the app. I was concerned I was setting the alarm to close to when i set it up.
Something to remember is the AlarmManager bunches the alarms up and fires them at the same time if they are close together (with the setRepeating method not setExact), this is to save batteries and no wake the phone up every minute or two.
i did the test with the above code and it started to work more normally. set up 4 alarms 1 minute apart, 3 of them went off at the same tome when the 3rd one was supposed to go off (which is correct behavior because they get bunched up to one to save batteries) and the last one went off very late 3-5 minutes after it was supposed to (which is fine, no problem).
So perhaps the problem is after i canceled an alarm and start a new one the AlarmManager is getting confused (when i was setting the alarm before, to close to when i set it up) and trying to group the canceled one and the one that is supposed to go off and making the not canceled one go off twice? sounds odd but perhaps Alarm are somewhat bugged???
Ok Im not 100% sure why the alarm was triggering the same one three times, but when i give more time for the alarm to run (say 5 minutes in the future apposed to 3 minutes), giving it more time seemed to solve lot of problems. feeling a little silly now for not giving it more time in the first place but every test takes 5 minutes to run, lots of waiting, which is annoying but works better now.
in the post:
setRepeating() of AlarmManager repeats after 1 minute no matter what the time is set (5 seconds in this case, API 18+)
it is mentioned:
"As of I think Android 5.1 (API version 22) there is a minimum period of 1 minute for repeating alarms, and alarms cannot be set less than 5 seconds in the future"
I was definitely within that time(or not within that time rather, more that 5 seconds), but increasing the alarm set further in the future fixed my issue.
UPDATE: during testing I set my initial timer time to several days in the past, I have noticed that if it passed the interval even if the timer was not set than it will trigger a notification as several times as it passed those intervals from the time it was set from even if the alarm was not actually set at or before that time, so that's why i was getting those extra notifications, i assume there is a limit of 2 alarms (with the same requestCode) that it can go off like this.

Setting alarm on daily basis

I am developing an android app where I am trying to set an alarm on daily basis.And for that I am using Calendar as
alarmCalendar.set(Calendar.DATE,taskdate);
alarmCalendar.set(Calendar.MONTH, 7);
alarmCalendar.set(Calendar.YEAR, 2013);
alarmCalendar.set(Calendar.HOUR, 11);
alarmCalendar.set(Calendar.MINUTE, 30);
alarmCalendar.set(Calendar.SECOND, 0);
I was setting the alarm using the below code.
alarmtime = alarmCalendar.getTimeInMillis();
am.setRepeating(AlarmManager.RTC_WAKEUP, alarmTime, AlarmManager.INTERVAL_DAY, pi);
The Problem with the above code is, the alarm triggers sometimes and sometimes it doesn't.
So I am trying it out in one more way. that is,
Once the alarm triggers, On cancel of that alarm I am trying to set it for the next day using
am.set(AlarmManager.RTC_WAKEUP, currenttime, pendingIntent);
instead of am.setRepeating(). But now the problem is that, even though there is no looping in the code, the alarm triggers continuously on cancelling it.
Not getting where I am going wrong.
Please Help.Thanks!
Do you have a BroadcastReceiver with the BOOT_COMPLETED permission to recreate the alarm every time the phone starts up? Otherwise you'll loose the alarm.
Check it out here http://learnandroideasily.blogspot.nl/2013/07/bootcompleted-broadcastreceiver-in.html

Call a method every x minutes

currently I have a application which can send notifications, I would like this application to be able to send these notifications automatically every x minutes (for example, 15 minutes is the default). The app may or may not be currently running when this notification should be sent.
After some reading, I've determined that an AlarmManager would be used here, but I cannot figure out how to call a method from it. I already have the notification code, I just need a way to call it every x minutes.
I'm very new to this, this is my first practice app (having experience in C#, but little in Java).
Thanks, David.
You might want to consider something like this:
Intent intent = new Intent(this, MyService.class);
PendingIntent pintent = PendingIntent.getService(this, 0, intent, 0);
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
// Start every 30 seconds
alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 30*1000, pintent);
If you are unclear, go through this tutorial
Write a IntentService. Inside it, just start a new Thread. In the Thread.run(), put an infinite while loop to call your notification code and Thread.sleep(15 * 60 * 1000)....
If you want to schedule your tasks with the specified interval don't use flags AlarmManager.RTC and AlarmManager.RTC_WAKEUP with method alarm.setRepeating(...). Because in this case alarm will be bounded to the device's real time clock. So changing the system time may cause alarm to misbehave. You must use flags AlarmManager.ELAPSED_REALTIME or AlarmManager.ELAPSED_REALTIME_WAKEUP. In this case SystemClock.elapsedRealtime() will serve as a basis for scheduling an alarm.
The code will look like:
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + checkIntervalMillis, checkIntervalMillis, pendingIntent);
If you want your long running task to be executed when device in the sleep mode I recommend to use WakefulIntentService library by CommonsWare: https://github.com/commonsguy/cwac-wakeful

Categories