Repeating Alarm for specific days of week android

2019-02-06 16:48发布

问题:

In my application I have a functionality to trigger alarm in 4 senerios:

  • Only once for a user chosen date and time
  • Daily for chosen time
  • Weekly according to chosen date and time
  • User chosen custom days of the week

I successfully implement the first 3 senerios by using the follow:

Only once:

Calendar calendar = Calendar.getInstance();

        calendar.set(Calendar.YEAR, Integer.parseInt(date[0]));
        calendar.set(Calendar.MONTH, (Integer.parseInt(date[1])) - 1);
        calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(date[2]));
        calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(time[0]));
        calendar.set(Calendar.MINUTE, Integer.parseInt(time[1]));
        calendar.set(Calendar.SECOND, 0);

        alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);

For daily scheduling:

Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(System.currentTimeMillis());
            calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(time[0]));
            calendar.set(Calendar.MINUTE, Integer.parseInt(time[1]));
            calendar.set(Calendar.SECOND, 0);

            alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);

For weekly scheduling (as per system date):

Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());

        calendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);
        calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(time[0]));
        calendar.set(Calendar.MINUTE, Integer.parseInt(time[1]));
        calendar.set(Calendar.SECOND, 0);
        //long interval = calendar.getTimeInMillis() + 604800000L;
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY * 7, pendingIntent);

For custom weekdays chosen by user (ex. only for monday and friday, repeated weekly) I am using the same code that I used for weekly scheduling by iteration. But its not working for monday (which is set before friday) and working for friday. Also, it does not trigger the alarm for today if today (system date) is a monday or a friday.

So how do i implement weekly alarm scheduling for custom days of the week?

回答1:

There isn't a way for you to tell Alarm manager which days you want to it trigger.

One solution would be to have an alarm for each day of the week you want it to trigger repeating weekly.

So for your Monday and Friday scenario, you would set a weekly repeating reminder on Monday and a weekly repeating reminder on Friday.

Example code:

private void scheduleAlarm(int dayOfWeek) {

    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);

    // Check we aren't setting it in the past which would trigger it to fire instantly
    if(calendar.getTimeInMillis() < System.currentTimeMillis()) {
        calendar.add(Calendar.DAY_OF_YEAR, 7);
    }

    // Set this to whatever you were planning to do at the given time
    PendingIntent yourIntent; 

    AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY * 7, yourIntent);
}

private void setUpAlarms() {

    scheduleAlarm(Calendar.MONDAY);
    scheduleAlarm(Calendar.FRIDAY);
}


回答2:

1) sunday=1, moday=2;, tuesday=3,......saturday=7  
2)selectedDays.size()*(it will be which date you have selected , if you seleted monday , tues ,friday , then it will 3 size )*    

3) for time if we choose from datetimepicker  
 **String[] timespilt = tv_timepicker.getText().toString().split(":");**


     for (int i = 0; i < selectedDays.size(); i++) {

         // for alarm ...
           calNow = Calendar.getInstance();
           calSet = (Calendar) calNow.clone();

            int day = calSet.get(Calendar.DAY_OF_WEEK); 
        calSet.set(Calendar.HOUR_OF_DAY,Integer.parseInt(timespilt[0].trim()));
                                        calSet.set(Calendar.MINUTE, Integer.parseInt(timespilt[1].trim()));
                                        calSet.set(Calendar.SECOND, 0);
                                        calSet.set(Calendar.MILLISECOND, 0);
                                        calSet.set(Calendar.DAY_OF_WEEK,selectedDays.get(i));


                                    if (calSet.compareTo(calNow) <= 0) {
                                        //Today Set time passed, count to tomorrow
                                        calSet.add(Calendar.DATE,7);

                                    }



                            System.out.println("set time for alarmweekly==="+calSet.getTime());
                            AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
                            PendingIntent alarmPI = PendingIntent.getBroadcast(this, (int) insertedId+selectedDays.get(i), alarmIntent,  0);

                            alarmManager.set(AlarmManager.RTC_WAKEUP, calSet.getTimeInMillis(), alarmPI);

                            alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                                    calSet.getTimeInMillis(), (DateUtils.DAY_IN_MILLIS) * 7,
                                    alarmPI);
}


回答3:

You have said that you used the same code of your weekly scheduling, "by iteration". If I understand you are trying to set multiple alarm (two in your example) with the same PendingIntent.

The problem is that as the documentation says

When you set a second alarm that uses the same pending intent, it replaces the original alarm.

This is way only the second alarm is triggered.

So in order to solve your problem you simply need to use a different PendingIntent for each scheduling.



回答4:

This will solve your problem.

private void scheduleAlarm(int dayOfWeek) {

        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);

        // Accept the change here at this line to avoid skipping of current week.
        if(calendar.getTimeInMillis() < System.currentTimeMillis()) {
             calendar.add(Calendar.DAY_OF_YEAR, new GregorianCalendar().get(Calendar.DAY_OF_WEEK)-1);
        }

        // Set this to whatever you were planning to do at the given time
        PendingIntent yourIntent; 

        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY * 7, yourIntent);
    }

    private void setUpAlarms() {

        scheduleAlarm(Calendar.MONDAY);
        scheduleAlarm(Calendar.FRIDAY);
    }

Thing to focus here to avoid skipping current week. :

calendar.add(Calendar.DAY_OF_YEAR, new GregorianCalendar().get(Calendar.DAY_OF_WEEK)-1);