In my code the Interval ( third parameter) on setRepeating() method seems not firing every 5 sec .
It keeps increasing in time, it's like the first one or 2 are mostly in time but the others fires like after 40+secs
So what's wrong here?
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent i = new Intent(this, MainActivity2Activity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pi = PendingIntent.getActivity(this, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE );
am.setRepeating(RTC_WAKEUP,System.currentTimeMillis(),1000*5,pi);
}
}
Take a look here: http://developer.android.com/reference/android/app/AlarmManager.html#setRepeating(int, long, long, android.app.PendingIntent)
As you're firing alarm every 5 seconds:
Note: for timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler.
Your code is ok. Explanation of a delay you're experiencing may be:
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.
From what I understand from your code you are trying to run MainActivity2Activity.class 5 seconds after the creation of MainActivity.class.
I would advice you to use FLAG_UPDATE_CURRENT instead of FLAG_CANCEL_CURRENT in your pending intent.
The FLAG_CANCEL_CURRENT would retain your first ever pending intent and won't update or create a new one until and unless you cancel the original pending intent first.
Using FLAG_UPDATE_CURRENT will ensure that the pending intent is updated every time MainActivity.class is executed, so that pending intent will be fired exactly after 5 seconds the MainActivity.class is created.
Hope this helps.
Basically you wrote PendingIntent.FLAG_CANCEL_CURRENT instead of PendingIntent.FLAG_ONE_SHOT.
Code for Set Alarm by Alarm Manager
AlarmManager alarmManager = (AlarmManager) getBaseContext().getSystemService(ALARM_SERVICE);
Intent i1 = new Intent(this, ReceiveAlarmActivity.class);
i1.putExtra("Key", "Value");
PendingIntent operation = PendingIntent.getActivity(getBaseContext(), 0, i1, PendingIntent.FLAG_ONE_SHOT);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, Your_Date.getTime(), 5000 operation);
You have to pass Your Date.
Done
Related
Ive been searching for how to using multiple alarms, and did find post in Stackoverflow, but never a straightful answer.
Im trying to set multiple alarms who will call a receiver class (AlarmBcast in my case) and, according to which alarm triggered the call, take different actions.
At this point I followed my way creating diferent receicer classes for each alarm call (and thus a different Intent, each with his own PendintIntent).
I read someone in other thread suggested making a stack (list) of alarms visible, and so using one receiver class for all alarms, but that is not an approach I would like to take.
There is a way to "see" which pendingintent was responsible for the call?.
only the intent is passed, but as there is only one, cant get which call was from it.
Before taking the way of the multiple receivers, this is how my code(pseudo) looked
Setting the alarms...
public class SelectedService extends Service {
//get dates from main
//do some date math
AlarmManager alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
Intent _myIntent = new Intent(this, AlarmBcast.class);
//setting Alarm A
PendingIntent _myPendingIntent = PendingIntent.getBroadcast(this, 123, _myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.RTC_WAKEUP, partidocalendar.getTimeInMillis(),_myPendingIntent);
//setting Alarm B
PendingIntent _myPendingIntent2 = PendingIntent.getBroadcast(this, 124, _myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.RTC_WAKEUP, convopartidocalendar.getTimeInMillis(),_myPendingIntent2);
//setting Alarm C
The receiver as i wa planning it ...
public class AlarmBcast extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//how to identify call A from B ??
if(AlarmA){}
if(AlarmB){}
}
Maybe i have some conceptual mistake? Back to programming since after 15 years (mostly assembler before)
You can put an "extra" in the Intent that identifies which alarm it is. For example:
_myIntent.putExtra("alarm", "A");
Do this before calling PendingIntent.getBroadcast() for each different alarm.
Then, in your BroadcastReceiver.onReceive() you can check the "extra" in the Intent to determine which alarm got triggered.
I fixed this issue by separating and creating two different Notification Channel and Classes
Following code works perfectly for Activity:
Intent intent = new Intent(context, MyActivity.class);
PendingIntent operation = PendingIntent.getActivity(context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
alarmmanager.setExact(AlarmManager.RTC_WAKEUP,
startTime.getTimeInMillis(),
operation);
However, when I do the same thing for IntentService, It works only if startTime and time I set alarm are on the same day. e.g. If I set the alarm today for 5 PM, it will be executed but when I set the alarm today for 5 PM tomorrow, it will not be executed. If this was Activity then it works for both cases.
Intent intent = new Intent(context, MyService.class);
PendingIntent operation = PendingIntent.getService(context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
alarmmanager.setExact(AlarmManager.RTC_WAKEUP,
startTime.getTimeInMillis(),
operation);
How to solve this?
The goal here I am trying to achieve is to execute IntentService every day at the exact time.
The goal here I am trying to achieve is to execute IntentService every day at the exact time.
Google has made this progressively harder from release to release. See Android AlarmManager setExact() is not exact. There could be two ways to solve this for your case:
you start an activity, which starts the service (as starting an Activity seems to work for you)
you use either setExactAnd... or setAlarmClock. setAlarmClock also triggers in the new "doze" mode, see https://stackoverflow.com/a/47049705/1587329.
Another way would be to re-think why and if you really need this... or if a JobScheduler could not fit your purpose more easily.
add replace your line with this line :
alarmmanager.setRepeating(AlarmManager.RTC_WAKEUP,
startTime.getTimeInMillis(),
operation);
it will repeat on specific interval you set in alarm manager
Replace the AlarmManager with this code:
alarmManager.setRepeating(AlarmManager.RTC,
timeMills,
AlarmManager.INTERVAL_DAY,
pendingIntent);
Worked for me.
HERE IS a DETAILED ANSWER check link in the bottom for more details.
Hope this will help. Your issue can be probably related to android versions too so do check the link for more details
app gets an instance of the AlarmManager and sets an alarm using a PendingIntent. More on usage and setting alarms is coming in the next section. The AlarmManager is the app side interface to the backing AlarmManagerService. It abstracts the details of the Binder interface, used to communicate with the system process (system_server) hosting the AlarmManagerService. These two components manage the alarm(s) the app has set and will send the PendingIntent correctly. This manager/service architecture is used throughout Android framework and is done for security and isolation purposes. The system_server process is running with privileges which normal apps do not have. If you are unfamiliar with Android’s use of permissions, see this article for more details on app processes and user IDs. These extra permissions are what allows system_server to access the underlying kernel alarm driver. The alarm driver is what manages setting alarms to wake up the device regardless of the sleep state of the SoC.
When the alarm is triggered the device is awakened (if asleep) and the AlarmManagerService is notified of an alarm expiring. It will then send the PendingIntent accordingly. This will cause the appropriate component within MyApp to be activated. If MyApp has not been started or its process is not cached, it will be started so the component can be activated.
basic usage will be as
public class MyActivity extends Activity {
...
private AlarmManager mAlarmMgr;
...
public void onCreate(Bundle savedInstance) {
...
mAlarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
...
}
...
}
let’s create a PendingIntent for our MyActivity using the component name.
Intent alarmIntent = new Intent(context, MyActivity.class);
PendingIntent pend = PendingIntent.getActivity(context,
0,
alarmIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
Now that we have our PendingIntent and the AlarmManager, we can set our alarm so our Activity is triggered when the alarm has expired. To do this, we need to figure out when we want our alarm to go off and whether it should wake up the device or just be delivered the next time the device is awakened. Remember, we have two different ways of specifying time for our alarms: elapsed time or calendar (RTC) time. So our options are ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC or RTC_WAKEUP. The _WAKEUP variants are our “aggressive” alarms where we want the device to come out of low power to call our app back. For our sample app, let’s set this up in a custom BroadcastReceiver and have it trigger our Activity about 30 seconds after the device is booted
public class MyBootReceiver extends BroadcastReceiver {
public void onReceive(Context, context, Intent intent) {
...
AlarmManager alarmMgr =
(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
long wakeTime = SystemClock.elapsedRealtime() + 30000;
alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeTime, pend);
}
}
Now when our device boots and the BOOT_COMPLETED broadcast is sent, our app’s process will be started and our receiver will set an alarm to trigger our Activity to be launched about 30 seconds later. Note that on Android 3.1 devices or newer, you must first manually launch your app before the BOOT_COMPLETED.
CREDIT GOES to writer of this BLOG
if you want to set the repeated alarm using SetExact you are bound to stop all other pending intents on the same time check this link for that here are many examples of how to do it! again credit goes to this writer
this is a very dumb question and I still cannot figure out how does AlarmManager work in Android. Suppose I want to schedule a repeating task every half an hour. I want to schedule it at activity onCreate(). I do something like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
AlarmManager.INTERVAL_HALF_HOUR,
AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);
}
Now my question is how does OS knows that this alarm has already been scheduled? I mean it is not scheduling a new one every time activity creates, is it? Otherwise, after 10 activity launches I would get alarm every three minutes and not half an hour. Please, any Android guru, explanation about the issue.
Now my question is how does OS knows that this alarm has already been scheduled?
AFAIK, it looks for an existing alarm for an equivalent PendingIntent. Here, by "equivalent PendingIntent", I mean:
the same operation (e.g., getBroadcast())
the same ID (second parameter to getBroadcast())
an equivalent Intent
Here, by "equivalent Intent", I mean that they match on all the routing information, which in your case is the ComponentName generated from this and AlarmReceiver.class. Extras, in particular, do not count for equivalence here.
I have created a configure activity for my widget, where the user can choose from various update frequencies.. Until now I started the alarm in the OnEnabled() method, like this:
Intent intent = new Intent(CLOCK_WIDGET_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC, System.currentTimeMillis(), 1000 * 60,
pendingIntent);
The settings are saved in shared preferences with a unique name (widgetId) and in this OnEnabled() method I can't retrieve the settings here because I can't get the widgetId yet.
There's an another problem, the user can change the frequency anytime, but this method is called just once, at the beginning. So I think I need to start the alarm in OnUpdate(), but I don't know how to do it, I don't want to make multiple instances of an alarm accidentally so I would like to ask for some advice.
To answer your second problem, calling setRepeating multiple times will not create multiple alarm as far as you provide same PendingIntent and same request code along with PendingIntent.FLAG_UPDATE_CURRENT flag. I would also suggest to use setInexactRepeating instead of setRepeating. So you can use the same code in OnUpdate() too with new frequency. Go through docs of FLAG_UPDATE_CURRENT and setInexactRepeating for more detials.
I've searched for 3 days now but didn't find a solution or similar problem/question anywhere else. Here is the deal:
Trigger in 1 hour -> works correct
Trigger in 2 hours -> Goes of in 1:23
Trigger in 1 day -> Goes of in ~11:00
So why is the AlarmManager so unpredictable and always too soon? Or what am I doing wrong? And is there another way so that it could work correctly?
This is the way I register my PendingIntent in the AlarmManager (stripped down):
AlarmManager alarmManager = (AlarmManager)parent.getSystemService(ALARM_SERVICE);
Intent myIntent = new Intent(parent, UpdateKlasRoostersService.class);
PendingIntent pendingIntent = PendingIntent.getService(parent, 0, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
//Set startdate of PendingIntent so it triggers in 10 minutes
Calendar start = Calendar.getInstance();
start.setTimeInMillis(SystemClock.elapsedRealtime());
start.add(Calendar.MINUTE, 10);
//Set interval of PendingIntent so it triggers every day
Integer interval = 1*24*60*60*1000;
//Cancel any similar instances of this PendingIntent if already scheduled
alarmManager.cancel(pendingIntent);
//Schedule PendingIntent
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, start.getTimeInMillis(), interval, pendingIntent);
//Old way I used to schedule a PendingIntent, didn't seem to work either
//alarmManager.set(AlarmManager.RTC_WAKEUP, start.getTimeInMillis(), pendingIntent);
It would be awesome if anyone has a solution. Thanks for any help!
Update:
2 hours ago it worked to trigger it with an interval of 2 hours, but after that it triggered after 1:20 hours. It's getting really weird. I'll track the triggers down with a logfile and post it here tomorrow.
Update:
The PendingIntent is scheduled to run every 3 hours. From the log's second line it seems like an old scheduled PendingIntent is still running:
[2012-5-3 2:15:42 519] Updating Klasroosters
[2012-5-3 4:15:15 562] Updating Klasroosters
[2012-5-3 5:15:42 749] Updating Klasroosters
[2012-5-3 8:15:42 754] Updating Klasroosters
[2012-5-3 11:15:42 522] Updating Klasroosters
But, I'm sure I cancelled the scheduled PendingIntent's before I schedule a new one. And every PendingIntent isn't recreated in the same way, so it should be exactly the same. If not , this threads question isn't relevant anymore.
When using a calendar are you taking into account that the calendar uses the time right down to Milli seconds. Maybe you should set the Milli second field and the seconds field to zero so it's going of on the dot.
Also for a day it would be easier to use this
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(0);
cal.add(Calendar.DAY_OF_MONTH, 1);
Also when you use getInstance doesn't that set the calendars time to the time it was created so there shouldn't be any need to set the time again right?
Rewrite: I eventually saw your error, but unpredictably.
I did changed this:
PendingIntent.getService(parent, 0, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
to this:
PendingIntent.getService(parent, 0, myIntent, PendingIntent.FLAG_CANCEL_CURRENT);
under the same assumption as you that somehow an old intent is broadcasting. I haven't seen the fluke since...
Also the only times I saw it were during my initial call. Another approach could be to track a current and a previous Calendar object, if the interval isn't what you expected then ignore this "early" broadcast. (While this method seems redundant considering how the alarm should work, it helps prevent those extraneous calls considering how the alarm is working...)
Hope that helps, I'll let you know if I find anything else.
I know this question is a bit old, but I had this same problem myself. I found out that if I tried to declare the Calendar variable outside of the method, it wouldn't play nicely and the alarms would fire early. Because your class is stripped down it is hard to tell exactly where you're calling the calendar instance.
If I set it up as such, then it would fire right on time:
protected void nextAlarm(Context context, int seconds){
Calendar nextAlarm = Calendar.getInstance();
Intent intent = new Intent(context, MyClass.class);
PendingIntent pending = PendingIntent.getBroadcast(context, MainActivity.REPEATING_ALARM, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager amanager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
nextAlarm.add(Calendar.SECOND, seconds);
amanager.set(AlarmManager.RTC_WAKEUP, nextAlarm.getTimeInMillis(), pending);
}
Make sure your service's onStartCommand returns START_NOT_STICKY, otherwise it will be automatically re-attempted:
public class UpdateKlasRoostersService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
buildUpdate();
return START_NOT_STICKY;
}
}