In Android Alarm Manager, how can we schedule multiple alarms which are non-repeating and do not have fixed intervals to repeat? I cannot use 'setRepeating' function as the alarms don't have any repeating pattern.
I have the alarm times stored in Sqlite database table and the activity should pick the date and time from this table and set the alarms.
If we setup different alarms in a loop, then it retains only the last one. I read from the post: How can create more than one alarm?
It tells to attach the unique Id to the intent and then setting up individual alarm events. But it didn't work for me.
Is there something we need to add in Manifest file to take care of this unique id?
The code in the activity 'RegularSchedule' is and it creates only one alarm event:
while (notifCursor.moveToNext()) { Intent intent = new Intent(RegularSchedule.this, RepeatingAlarm.class); // The cursor returns first column as unique ID intent.setData(Uri.parse("timer:" + notifCursor.getInt(0))); PendingIntent sender = PendingIntent.getBroadcast( RegularSchedule.this, 0, intent, 0); // Setting time in milliseconds taken from database table cal.setTimeInMillis(notifCursor.getLong(1)); AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE); am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender); }
Please let me know if further details or code snippets are required.
Manifest file (here RepeatingAlarm extends BroadcastReceiver):
<receiver android:name=".user_alerts.RepeatingAlarm" android:process=":remote" /> <activity android:name=".user_alerts.RegularSchedule" android:label="@string/reg_schedule_title" android:theme="@android:style/Theme.Light"> </activity>
RepeatingAlarm:
public class RepeatingAlarm extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); ....... // The PendingIntent to launch our activity if the user selects this notification Intent notificationIntent = new Intent (context, DisplayReminder.class); PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0); // Set the info for the views that show in the notification panel. notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent); notification.defaults |= Notification.DEFAULT_SOUND; notification.defaults |= Notification.DEFAULT_VIBRATE; notification.defaults |= Notification.DEFAULT_LIGHTS; mNotificationManager.notify(2425, notification);
You can also use the AlarmManager to schedule repeating alarms, using one of the following methods: setRepeating() : Prior to Android 4.4 (API Level 19), this method creates a repeating, exactly timed alarm. On devices running API 19 and higher, setRepeating() behaves exactly like setInexactRepeating() .
The AlarmManager service is a convenient class to schedule working on your Android application; however, when the device shuts down or reboots, all your alarms will be lost since the system does not retain them between system restarts.
Open your phone's Clock app . At the bottom, tap Alarm. On the alarm you want, tap the Down arrow . Cancel: To cancel an alarm scheduled to go off in the next 2 hours, tap Dismiss.
If you want to set multiple alarms (repeating or single), then you just need to create their PendingIntent s with different requestCode . If requestCode is the same, then the new alarm will overwrite the old one.
This is what worked for me. I'm sharing the solution so that others can benefit and find quick solution to this problem.
I welcome any other inputs to throw more light on the technicality of the solution and why certain things work and others don't :)
(1) First of all, Manifest file: Make sure that you have receiver for your class having BroadcastReceiver.
<receiver android:name=".RepeatingAlarm" android:process=":remote"> <intent-filter> <data android:scheme="timer:" /> </intent-filter> </receiver>
Please note that the class is part of main package. If it is in some sub-package, please move to the main package. The main package is what you define in 'manifest' tag.
'intent-filter' is used to define 'action' and 'data'. You can put the Activity class here which is going to be called from your pending intent. But I found that if you define 'action' in manifest, it doesn't display dynamic values on the activity. It just shows static values. Quite strange. If you get in same issue, don't put 'action' in manifest, rather put it in BroadcastReceiver class as part of pending intent.
'data' tag is what you are going to put dynamic URI of unique intents while scheduling different alarms using AlarmManager. Please refer next steps for more details.
(2) Activity Class in which you are going to use AlarmManager to schedule alarms: I'm using the database to store my alarm time values and then scheduling using those values. My cursor fetches the unique _ID from the table and alarm time (in seconds since 1/1/1970). See that the URI put here is same as what you have in manifest file.
Calendar cal = Calendar.getInstance(); int notifIterator = 0; if (notifCursor.getCount() > 0) { while (notifCursor.moveToNext()) { Intent intent = new Intent(MySchedule.this, RepeatingAlarm.class); // As the same intent cancels the previously set alarm having // same intent // changing the intent for every alarm event so that every alarm // gets // scheduled properly. intent.setData(Uri.parse("timer:" + notifCursor.getInt(0))); PendingIntent sender = PendingIntent.getBroadcast( MySchedule.this, 0, intent, Intent.FLAG_GRANT_READ_URI_PERMISSION); cal.setTimeInMillis(notifCursor.getLong(1) * 1000); AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE); am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender); notifIterator++; Toast mToast = Toast.makeText( RegularSchedule.this, "Reminders added to the calendar successfully for " + android.text.format.DateFormat.format( "MM/dd/yy h:mmaa", cal.getTimeInMillis()), Toast.LENGTH_LONG); mToast.show(); } }
If you don't see alarms even after doing this, check the timezone which emulator takes. Sometimes, we schedule for Local Timezone, but emulator schedules for GMT timezone. If you look at toast message, that will help you figure out this problem.
(3) Last one is BroadcastReceiver class. Please note that to open database, you will require to use the 'context':
public void onReceive(Context context, Intent intent) { // Update the status in the notification database table int notificationId = Integer.parseInt(intent.getData().getSchemeSpecificPart()); db = context.openOrCreateDatabase(DATABASE_NAME, SQLiteDatabase.CREATE_IF_NECESSARY, null); <<<< Do DB stuff like fetching or updating something>>>> // Raise the notification so that user can check the details NotificationManager mNotificationManager = (NotificationManager) context .getSystemService(Context.NOTIFICATION_SERVICE); int icon = R.drawable.icon; CharSequence tickerText = "your text"; long when = System.currentTimeMillis(); Notification notification = new Notification(icon, tickerText, when); // Count of number of notifications notification.number = notifCount; CharSequence contentTitle = "your title "; CharSequence contentText = "your notification text"; // The PendingIntent to launch our activity if the user selects this // notification Intent notificationIntent = new Intent(context, DisplayReminder.class); PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0); // Set the info for the views that show in the notification panel. notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent); notification.defaults |= Notification.DEFAULT_SOUND; notification.defaults |= Notification.DEFAULT_VIBRATE; notification.defaults |= Notification.DEFAULT_LIGHTS; // Instead of 1234 or any other number, use below expression to have unique notifications // Integer.parseInt(intent.getData().getSchemeSpecificPart()) mNotificationManager.notify(1234, notification); }
Note that if you want to create separate notification, the request id can be passed as unique when calling notify().
Finally, you can create DisplayReminder class which you want to call when user clicks on notification.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With