8

Currently I am working on an application to set reminders on monthly basis. I am not able to provide the correct repeating interval for my alarmmanager. Pls provide info about the same. this is my code, but this will not raise alarm for Feb or months having 30 days. Also pls provide code to set yearly repeating alaram.

repeatTime=(AlarmManager.INTERVAL_DAY*31);
mAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, when.getTimeInMillis(), repeatTime, pi);

Thanks, Sharath

sharath reddy
  • 93
  • 1
  • 7
  • check this link for monthly repeating alarm [here][1] [1]: http://stackoverflow.com/questions/26645749/android-repeating-alarm-should-repeat-on-monthly-basis-and-on-same-day-for-each/26646069#26646069 – mushahid Oct 30 '14 at 06:08

5 Answers5

9

this is how you calculate interval between today in extacly one month after, use this logic to reset alarm everytime once it triggers. i.e set alarm to the point when you want to start, supply some pending intent, once alarm triggers use below code to get next trigger time, and set alarm again to trigger at that time.

private long getDuration(){
    // get todays date
    Calendar cal = Calendar.getInstance();
    // get current month
    int currentMonth = cal.get(Calendar.MONTH);

    // move month ahead
    currentMonth++;
    // check if has not exceeded threshold of december

    if(currentMonth > Calendar.DECEMBER){
        // alright, reset month to jan and forward year by 1 e.g fro 2013 to 2014
        currentMonth = Calendar.JANUARY;
        // Move year ahead as well
        cal.set(Calendar.YEAR, cal.get(Calendar.YEAR)+1);
    }

    // reset calendar to next month
    cal.set(Calendar.MONTH, currentMonth);
    // get the maximum possible days in this month
    int maximumDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);

    // set the calendar to maximum day (e.g in case of fEB 28th, or leap 29th)
    cal.set(Calendar.DAY_OF_MONTH, maximumDay);
    long thenTime = cal.getTimeInMillis(); // this is time one month ahead



    return (thenTime); // this is what you set as trigger point time i.e one month after

}
Techfist
  • 4,314
  • 6
  • 22
  • 32
  • Hi thanks for your response, I tested this by changing the date to next month and it was working, I have one more issue whenever we restart the emulator it is raising alaram for all the missed alaram. Could you please tell me how to implement how to raise alaarams only for which are not raised? Thanks, Sharath – sharath reddy Sep 16 '14 at 07:18
  • you can supply some data in intent, such as timestamp of trigger, once your alarm is raised, you would receive the same back in intent, with this you can write your logic of checking weather its previous alrams which were missed by comparing time. – Techfist Sep 16 '14 at 08:44
  • currently i am storing the reminders in db. But not sure how to avoid raising duplicate alarams, could u pls provide any code snippet to do this. Thanks, Sharath – sharath reddy Sep 18 '14 at 07:08
  • can you post your code here, whatever you have tried. Am sorry but I need to know context in which your are talking before providing any help. – Techfist Sep 18 '14 at 13:09
  • I have created a app which is used for setting reminders. whenever a user sets a reminder it will store this in db. Once the device reboots it will forget the reminders right. So i have created a class which on reboot will fetch all the reminders and again set the reminders newly because old reminders will go off if the device reboots right. I don't want to raise duplicate alarams. – sharath reddy Sep 18 '14 at 13:38
  • pls tell me your email id i will send the code it is not allowing to paste the entire code here. – sharath reddy Sep 18 '14 at 13:41
  • Your solution is preety simple, see its true alarm managers clear everything once device is rebooted. for that you have created you db to hold reminder set by user, so in your db why dont you keep, alarm trigger time in a column as well, if you do this your only task will be, upon reboot just read all the rows whose trigger time values is larger then current time, and set those alarm again. isn't it, this will solve this right?. Also you can put your code into github, I will fork from there. – Techfist Sep 18 '14 at 16:43
  • This is exactly what I've been looking for. I don't know how to properly word out about dealing with setting the alarm every 30th of month then suddenly hits February which doesn't have that date. – Neon Warge Nov 14 '15 at 09:57
  • This method is works like a charm. Thanks @Techfist – Debasish Mondal Dec 17 '20 at 14:03
2

To set alarm which repeat monthly,

        Calendar calender= Calendar.getInstance(TimeZone.getDefault());
        int cDay = calender.get(Calendar.DAY_OF_MONTH);

        calender.set(Calendar.HOUR_OF_DAY, hour); //hour you have selected
        calender.set(Calendar.MINUTE, min); //min you have selected
        calender.set(Calendar.SECOND, 0);
        calender.set(Calendar.MILLISECOND, 0);

        calender.set(Calendar.DATE, cDay);
        calender.get(Calendar.MONTH);

        Calendar now = Calendar.getInstance();
        now.set(Calendar.SECOND, 0);
        now.set(Calendar.MILLISECOND, 0);

        int days = now.getActualMaximum(Calendar.DAY_OF_MONTH);

        if (calender.before(now)) {  //this condition is used for future alarm only
            calender.add(Calendar.DATE, days);
        }

        final int _id = (int) System.currentTimeMillis();

        Intent i = new Intent(activity, YourServiceClass.class);
        i.putExtra("type", "month");

        PendingIntent displayIntent = PendingIntent.getBroadcast(
                activity, _id, i, PendingIntent.FLAG_UPDATE_CURRENT);

        AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

        alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, calender.getTimeInMillis(), AlarmManager.INTERVAL_DAY * calender.getActualMaximum(Calendar.DAY_OF_MONTH), displayIntent);

Now in your service class , put below code

if (intent.getExtras() != null) {

        type = intent.getStringExtra("type");
    }

    if (type != null) {

        if (type.equals("month")) {

            Long futureTimeDifference = intent.getLongExtra("futureTimeDifference", 0); // Receive the time difference in milliseconds from currenttime in milliseconds and the future set date milliseconds
            futureTimeDifference = futureTimeDifference + System.currentTimeMillis();// get the next schedule date time inmilliseconds
            String repeatType = intent.getStringExtra("getRepeatType");// Receive the repeat type


            Date todaysDate = new Date();// initialize a new date object
            Calendar getCurrentDate = Calendar.getInstance();// Initialize a new Calendar object
            getCurrentDate.setTime(todaysDate); //Set the calendar to todays date
            int currentMonth = getCurrentDate.get(Calendar.MONTH); // Assign the current month in integer

            if (currentMonth == Calendar.JANUARY || currentMonth == Calendar.MARCH || currentMonth == Calendar.MAY || currentMonth == Calendar.JULY || currentMonth == Calendar.AUGUST || currentMonth == Calendar.OCTOBER || currentMonth == Calendar.DECEMBER) {
                futureTimeDifference = System.currentTimeMillis() + (AlarmManager.INTERVAL_DAY * 31);
            }
            if (currentMonth == Calendar.APRIL || currentMonth == Calendar.JUNE || currentMonth == Calendar.SEPTEMBER || currentMonth == Calendar.NOVEMBER) {
                futureTimeDifference = System.currentTimeMillis() + (AlarmManager.INTERVAL_DAY * 30);
            }

            if (currentMonth == Calendar.FEBRUARY) {//for february month)
                GregorianCalendar cal = (GregorianCalendar) GregorianCalendar.getInstance();
                if (cal.isLeapYear(cal.get(Calendar.YEAR))) {//for leap year february month
                    futureTimeDifference = System.currentTimeMillis() + (AlarmManager.INTERVAL_DAY * 29);
                } else { //for non leap year february month
                    futureTimeDifference = System.currentTimeMillis() + (AlarmManager.INTERVAL_DAY * 28);
                }
            }

            final int monthly_id = (int) System.currentTimeMillis();

            Log.e("MonthlyNotification", futureTimeDifference + "");

            PendingIntent displayIntent = PendingIntent.getBroadcast(
                    context, monthly_id, intent, PendingIntent.FLAG_UPDATE_CURRENT);

            AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);

            alarmManager.set(AlarmManager.RTC_WAKEUP, futureTimeDifference, displayIntent);

            //Toast.makeText(context, "Notification Set Monthly", Toast.LENGTH_SHORT).show();
        }
    }
0

for yearly repeating alarm

GregorianCalendar cal = (GregorianCalendar) GregorianCalendar.getInstance();
    if(cal.isLeapYear(year)){
      alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY * 366, alarmIntent);
    }else{
          alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY * 365, alarmIntent);
    }
mushahid
  • 504
  • 5
  • 21
0

Thanks Techfist .. ex: dateValue = "30/01/2017 11:02" ... get id and date from database ...

private void getMonthlyDuration(Context context,int id,String dateValue) {
    SharedPreferences sharedPreferences = context.getSharedPreferences("ModernDiary", Context.MODE_PRIVATE);
    String dateOfMonth = sharedPreferences.getString("day"+id,DateFormat.format("dd", Calendar.getInstance()).toString());
    Calendar calendar = Calendar.getInstance();
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm", Locale.getDefault());
    try {
        Date dateMain = simpleDateFormat.parse(dateValue);
        calendar.setTime(dateMain);
    } catch (ParseException e) {
        e.printStackTrace();
    }
    Boolean isSetDate = false;
     if (sharedPreferences.getInt("monthInc"+id,-1) != -1) {
         calendar.set(Calendar.MONTH,sharedPreferences.getInt("monthInc"+id,calendar.get(Calendar.MONTH)));
         calendar.set(Calendar.YEAR,sharedPreferences.getInt("yearInc"+id,calendar.get(Calendar.YEAR)));
         if (calendar.getActualMaximum(Calendar.DAY_OF_MONTH) < Integer.parseInt(dateOfMonth)) {
             calendar.set(Calendar.DATE,calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
             Log.i("timeDay",dateOfMonth+" "+calendar.getTime()+" max");
         } else {
             calendar.set(Calendar.DATE,Integer.parseInt(dateOfMonth));
             Log.i("timeDay",dateOfMonth+" "+calendar.getTime()+"min");
         }
         if (sharedPreferences.getInt("monthInc"+id,calendar.get(Calendar.MONTH)) < calendar.get(Calendar.MONTH)){
             calendar.add(Calendar.MONTH, -1);
             isSetDate = true;
             Log.i("timeMonth","Increment "+calendar.getTime());
         } else {
             isSetDate = false;
             Log.i("timeMonth","No Change");
         }
     }
    calendar.add(Calendar.MONTH, 1);
     if (isSetDate){
         if (calendar.getActualMaximum(Calendar.DAY_OF_MONTH) < Integer.parseInt(dateOfMonth)) {
             calendar.set(Calendar.DATE,calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
         } else {
             calendar.set(Calendar.DATE,Integer.parseInt(dateOfMonth));
         }
     }
    Log.i("timeAf",calendar.getTime()+"");

    sharedPreferences.edit().putInt("monthInc"+id, calendar.get(Calendar.MONTH)).apply();
    sharedPreferences.edit().putInt("yearInc"+id, calendar.get(Calendar.YEAR)).apply();
    Intent notificationIntent = new Intent(context,AlarmBroadcastReceiver.class);
    Bundle bundle = new Bundle();
    bundle.putSerializable("alarm", id);
    notificationIntent.putExtra("bundle", bundle);
    alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    broadcast = PendingIntent.getBroadcast(context, id, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), broadcast);
}

Alarm triggering times: Tue Feb 28 11:02:00 GMT+05:30 2017 Thu Mar 30 11:02:00 GMT+05:30 2017 Sun Apr 30 11:02:00 GMT+05:30 2017 Tue May 30 11:02:00 GMT+05:30 2017 Fri Jun 30 11:02:00 GMT+05:30 2017 Sun Jul 30 11:02:00 GMT+05:30 2017 Wed Aug 30 11:02:00 GMT+05:30 2017 Sat Sep 30 11:02:00 GMT+05:30 2017 Mon Oct 30 11:02:00 GMT+05:30 2017 Thu Nov 30 11:02:00 GMT+05:30 2017 Sat Dec 30 11:02:00 GMT+05:30 2017 Tue Jan 30 11:02:00 GMT+05:30 2018 Wed Feb 28 11:02:00 GMT+05:30 2018 ...

Rathiga Jesika
  • 357
  • 4
  • 16
0

You could use set and then resetting the alarm in broadcast receiver

in the receiver, simply:

        val c = Calendar.getInstance().apply { add(Calendar.MONTH, 1) }
        // reset alarm here
        val intent = Intent(context, AlarmReceiver::class.java)
        val pendingIntent = PendingIntent.getBroadcast(
            context, 123, intent, 0
        )
        val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager?
        alarmManager!!.set(
            AlarmManager.RTC,
            c.timeInMillis,
            pendingIntent
        )
Fajar Ulin Nuha
  • 399
  • 2
  • 7