alarmmanager 2 times

2019-07-09 00:19发布

问题:

I have a BroadcastReceiver called AlarmReceiver that Toasts "alarm worked". I'm trying to set up a repeating PendingIntent to trigger AlarmReceiver at 5:45 and 17:30, but I see "alarm worked" after few seconds of starting the app. Why is the PendingIntent getting sent immediately?

 public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Calendar cal1 = Calendar.getInstance();
        cal1.set(Calendar.HOUR_OF_DAY, 05);
        cal1.set(Calendar.MINUTE, 45);
        cal1.set(Calendar.SECOND, 00);

        Calendar cal2 = Calendar.getInstance();
        cal2.set(Calendar.HOUR_OF_DAY, 17);
        cal2.set(Calendar.MINUTE, 30);
        cal2.set(Calendar.SECOND, 00);

        Intent intent = new Intent(this, AlarmReceiver.class);

        PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), 0, intent,      PendingIntent.FLAG_UPDATE_CURRENT);
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal1.getTimeInMillis(),cal2.getTimeInMillis(), pi);


        Toast.makeText(this, "Alarm set", Toast.LENGTH_LONG).show();

    }


}

AlarmReceiver:

public class AlarmReceiver extends BroadcastReceiver {


        public void onReceive(Context context, Intent intent) {

            Toast.makeText(context, "Alarm worked.", Toast.LENGTH_LONG).show();

}

回答1:

but I see "alarm worked" after few seconds of starts of my app.

I believe you are receiving the first alarm just fine.

But you believe it is not repeating. This wrong, it will repeat... once every ~43 years. You are using the third parameter of setRepeating incorrectly, try:

Calendar cal1 = Calendar.getInstance(); // Now
cal1.add(Calendar.SECONDS, 5); // Change to five seconds from now

alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 
        cal1.getTimeInMillis(), 
        10000, /* Repeat every 10 seconds */ 
        pi);

The third parameter is an interval. This code creates an alarm that goes off in 5 seconds, then repeats every 10 seconds. By using cal2 you are accidentally setting the interval to almost 43 years.


To set two different alarms use:

Calendar cal1 = Calendar.getInstance();
cal1.set(Calendar.HOUR_OF_DAY, 05);
cal1.set(Calendar.MINUTE, 45);
cal1.set(Calendar.SECOND, 00);

Calendar cal2 = Calendar.getInstance();
cal2.set(Calendar.HOUR_OF_DAY, 17);
cal2.set(Calendar.MINUTE, 30);
cal2.set(Calendar.SECOND, 00);

// Test if the times are in the past, if they are add one day
Calendar now = Calendar.getInstance();
if(now.after(cal1))
    cal1.add(Calendar.HOUR_OF_DAY, 24);
if(now.after(cal2))
    cal2.add(Calendar.HOUR_OF_DAY, 24);

// Create two different PendingIntents, they MUST have different requestCodes
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent morningAlarm = PendingIntent.getBroadcast(getApplicationContext(), 0, intent, 0);
PendingIntent eveningAlarm = PendingIntent.getBroadcast(getApplicationContext(), 1, intent, 0);

// Start both alarms, set to repeat once every day
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal1.getTimeInMillis(), DateUtils.DAY_IN_MILLIS, morningAlarm);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal2.getTimeInMillis(), DateUtils.DAY_IN_MILLIS, eveningAlarm);


回答2:

As Sam's post says, you aren't using the right triggerAtMillis and intervalMillis. I think you are telling it to trigger at 5 am on the current day, which is likely in the past, in which case the documentation says that the

Calendar cal1 = Calendar.getInstance();
cal1.add(Calendar.HOUR, 5);
cal1.add(Calendar.MINUTE, 45);

long interval = 17 * 60 * 60 * 1000; // 17 hours converted to milliseconds
interval += 30 * 60 * 1000; // 30 minutes converted to milliseconds

Intent intent = new Intent(this, TestAlarmReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal1.getTimeInMillis(), interval, pi);

is probably what you want to do instead.

EDIT (more explanation):

cal1.add(Calendar.HOUR, 5); takes the current date and time and increases it by 5 hours, so the result is that the repeating PendingIntent will begin 5 hours and 45 minutes from the current time on this date. and the interval says that it will send the second and subsequent PendingItents every 17 hours and 30 minutes from then (where then is 5 hours and 45 minutes from now).

If you want to set the start to be 5:45 am, but don't want it to be sent immediately (unless it happens to be exactly 5:45 am at the moment). then you will want to set do:

cal1.set(Calendar.HOUR, 5);
cal1.set(Calendar.MINUTE, 45);
cal1.set(Calendar.SECOND, 0);

// Current time is after 5:45 am, don't start until tomorrow at 5:45
if (Calendar.getInstance().after(cal1))
    cal1.add(Calendar.DAY_OF_YEAR, 1)

Alternatively, you can compute the interval from that time to decide when it would be triggered next assuming it had already been started at 5:45, but that would take a bit more work to compute.