I'm trying to create a function in my App, which notifies the user at the expiration day of his rented books. I'll work with checkboxes in a listview, as below:
(Dates are for show purposes only)
Now i'm wondering how can i do it the best way. I'm having experiences with AlarmManager and BroadcastReceivers, but I didn't get a clear flowchart yet.
Thats because I need to set an specific alarm to each book and cancel that specific alarm when requested. Also, it needs to reactivate all Alarms when device is restared (by calling BOOT_COMPLETE broadcast).
PS.: Alarms will usually be set to one week after current date.
PS2.: Can I use Calendar to do it? I mean, this way i wouldn't have to reactivate all alarms, or calculate (expirationDate - currentDate) in millis.
Can someone, who has an idea, try to show me the way? Thanks!
I think the key would be to give each and every book its own alarm id as soon as you set the alarm for this book for the first time.
Then you should keep a list of the running alarm ids and timestamps (maybe in SharedPreferences).
With a method like this you can cancel a specific alarm with regards to its alarm id:
public static void cancelAlarm(Context context, int alarmId) {
PendingIntent pi = PendingIntent.getService(context, alarmId,
new Intent(context, YourService.class),
PendingIntent.FLAG_NO_CREATE);
if(pi!=null) {
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.cancel(pi);
}
}
When you receive the BOOT broadcast, you can get the list of alarm ids together with timestamps from SharedPreferences and start all the alarms with their respective alarm ids
Related
If I allow my user to schedule a notification using AlarmManager, and then they schedule another notification using the same code, will the first alarm be overridden? Or will both alarms be set?
When creating a pendingIntent you have to include an id:
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, ID , intent, Flags)
If the number in the ID location is always the same, then the alarm will be overridden. If it is the same then it will not be.
You can use the same code, as long as the ID is different. You can achieve this in many ways, like creating an ID based on the time you schedule the alarm for, as you may not need two alarms for the same time.
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 found a lot of examples and questions regarding how to fire an alarm using AlarmManager (both periodical or single), but nothing similar to what I need.
My user can schedule a certain number of events (i.e. things to do), with a single-shot alarm for each of them to be fired one day before the scheduled start (showing a notification). This is easy.
My problem is that this scheduled start can be changed, thus the alarm should be moved too.
I was thinking to delete the old alarm, and to create a new one considering the new scheduled start. Knowing that I can delete an alarm using alarmMgr.cancel(alarmIntent), how can I delete the specific alarm related to the rescheduling event? Should I make each alarmIntent unique in some way?
Or there is a better way that I didn't consider (except using Google Calendar APIs to schedule and reschedule an event there, and making it managing the notification)?
While scheduling an alarm using set() API
public void set (int type, long triggerAtMillis, PendingIntent operation)
in the last argument you can mention a request code using getBroadcast
public static PendingIntent getBroadcast (Context context, int requestCode, Intent intent, int flags)
an example for this would be :
alarm.set(AlarmManager.RTC_WAKEUP, time, PendingIntent.getBroadcast(mContext, id, intentAlarm, PendingIntent.FLAG_UPDATE_CURRENT));
When you want to cancel or reschedule you can use the 'id' to specify which alarm.
In my project, I have a database with Year, Month, Day, Hour, Minute. For each row in this database I want to put notification with Title and description for user in time, that described in that row, but when I use NotificationManager, it activates at once when I add new time to database. I read this article: Alarm Manager Example, about Alarm Manager Example, but I still can't understand, how to use it for notifications, because when I try to use, nothing happens. I'll be glad, if someone can help me.
Your message isn't clear to me. If you are trying to launch notifications at a certain time, this is one way to do it. Use 2 services; one service (you could call it SetAlarmService) to read your DB and set a pending intent to launch at a certain time with the AlarmManager. You can get an instance by calling getSystemService(Context.ALARM_SERVICE);. You should set your pending intent to launch another service (you could call it NotifyService), which will simply put up the notification as soon as it is started.
EDIT: here is a quick example, see the documentation for explanations of parameters, etc.
public class AlarmService extends Service {
Time time;
AlarmManager alarmMan;
#Override
public void onCreate() {
alarmMan = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
time = new Time();
}
#Override
public int onStartCommand(Intent intent, int startID, int flags) {
time.setToNow();
alarmMan.set(AlarmManager.RTC_WAKEUP, time.toMillis(false)+(10*1000), getPIntent());
time = null;
}
public PendingIntent getPIntent() {
Intent startIntent = new Intent(this, NotifyService.class);
startIntent.setAction(com.berrmal.remindme.NotifyService.ACTION_SEND_NOTIFICATION);
PendingIntent pIntent = PendingIntent.getService(this, 0, startIntent, PendingIntent.FLAG_CANCEL_CURRENT);
return pIntent;
}
I launch this service from an activity, you can do it any way you want. NotifyService.class is another service I have written that just immediately posts a sticky notification, I'm not going to show that because it sounds like you already know how to use the NotificationManager. The key here is the 10*1000, that is how many milliseconds in the future the alarm will be activated, and thus what time the notification will show up. You could read that from a file, etc. In this example, I am just calculating 10000 millis in the future from now. The RTC_WAKEUP flag is one of 4 flags that you will want to read about, they make the alarm do slightly different things. Hope that helps.
in my application users are free to select time and date to set alarms .
What will happen if user choose exactly the same date and time for two alarms.
I am taking input from user(for date and time) and setting the alarm.
GregorianCalendar gc=new GregorianCalendar();
gc.set(2012, 1, 22, 11, 19,0);//values as given by the user
final Intent intent = new Intent(this, AlarmService.class);
gc.set(Calendar.AM_PM,0);
// final PendingIntent sender = PendingIntent.getBroadcast(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
am.set(AlarmManager.RTC_WAKEUP, gc.getTimeInMillis(),PendingIntent.getBroadcast(this,1, intent, PendingIntent.FLAG_UPDATE_CURRENT));
I have used a broadcastreceiver to recieve the alarm broadcast.
How should I handle this situation. What should I prefer to do?
I want to know the tecchnical aspect as what happens in this situation.
AFAIK,it won't create any technical problem for alarms set for the same time.It will fire all alarms at the same time.
It depends upon you how you want your user to set alarm.If you want them to set same time for various alarms,it's not a problem.
But if you don't want them to repeat the alarm time once it is set for other,then you can store alarms' time in database and at the time of setting new one,you can check for the conflict of newly set alarm time with previously set alarms from database and reject if it is found same.