Как настроить Recurring AlarmManager для ежедневного выполнения кода

В настоящее время я пытаюсь написать диспетчер аварийных сигналов, который будет ежедневно срабатывать в течение определенного периода времени. Сначала я проверяю, установлен ли у пользователя будильник на этот день:

      if ((User.getReminderTime(Home.this) > 0)
    && (dt.getDate() != today.getDate() || dt.getDay() != today
      .getDay())) {
   AppointmentManager.setFutureAppointmentCheck(this
     .getApplicationContext());
   User.setLongSetting(this, "futureappts", today.getTime());
  }

Затем я иду и устанавливаю настоящий будильник на период с 12 до 12:10 следующего дня:

     public static void setFutureAppointmentCheck(Context con) {
  AlarmManager am = (AlarmManager) con
    .getSystemService(Context.ALARM_SERVICE);

  Date futureDate = new Date(new Date().getTime() + 86400000);
  Random generator = new Random();

  futureDate.setHours(0);
  futureDate.setMinutes(generator.nextInt(10));
  futureDate.setSeconds(0);

  Intent intent = new Intent(con, FutureAppointmentReciever.class);

  PendingIntent sender = PendingIntent.getBroadcast(con, 0, intent,
    PendingIntent.FLAG_ONE_SHOT);

  am.set(AlarmManager.RTC_WAKEUP, futureDate.getTime(), sender);

 }

Теперь я настраиваю тестовую среду, чтобы это срабатывало каждые две минуты, и, похоже, все работает нормально, однако, когда я развертываю на реальном устройстве, получатель, похоже, не получает сигналы тревоги. Я подумал, что это может быть проблема с спящим устройством, поэтому я добавил диспетчер питания. Но все равно не работает:

      PowerManager pm = (PowerManager) context
    .getSystemService(Context.POWER_SERVICE);
  PowerManager.WakeLock wl = pm.newWakeLock(
    PowerManager.PARTIAL_WAKE_LOCK, "keepAlive");
  wl.acquire();
  setFutureAppointments(context.getApplicationContext());
  AppointmentManager.setFutureAppointmentCheck(context
    .getApplicationContext());
  User.setLongSetting(context.getApplicationContext(), "futureappts",
    new Date().getTime());
  wl.release();

Кто-нибудь видит что-то, что я делаю явно неправильно, или я делаю это неправильно? Спасибо за любую помощь.


person ninjasense    schedule 13.12.2010    source источник


Ответы (2)


Обычно я делаю что-то большее, например:

Intent i = new Intent(this, MyService.class);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.cancel(pi); // cancel any existing alarms
am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
    SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_DAY,
    AlarmManager.INTERVAL_DAY, pi);

Таким образом, вам не нужно беспокоиться о перенастройке AlarmManager в вашем Service.

Обычно я запускаю этот фрагмент кода при запуске моего приложения (onResume в моем основном действии) и в BroadcastReceiver, настроенном на получение BOOT_COMPLETED.

Я написал руководство по созданию Service и использованию AlarmManager, которое основано на моем собственном опыте и нескольких советах и ​​рекомендациях, которые я выбрал, просматривая доклад Google I/O. Если вам интересно, вы можете прочитать это здесь .


Чтобы ответить на ваш вопрос ниже, все, что я могу сделать, это процитировать документы:

public void setInexactRepeating (int type, long triggerAtTime, long interval, PendingIntent operation)

Запланируйте повторяющийся сигнал тревоги с неточными требованиями к времени срабатывания; например, будильник, который повторяется каждый час, но не обязательно в начале каждого часа. Эти тревоги более энергоэффективны, чем строгие повторения, предоставляемые setRepeating(int, long, long, PendingIntent), поскольку система может регулировать фазу тревог, чтобы они срабатывали одновременно, избегая пробуждения устройства из спящего режима больше, чем это необходимо.

Первый срабатывание вашего будильника не произойдет раньше запрошенного времени, но может не сработать в течение почти полного интервала после этого времени. Кроме того, в то время как общий период повторяющегося будильника будет соответствовать запросу, время между любыми двумя последовательными срабатываниями будильника может варьироваться. Если ваше приложение требует очень низкого джиттера, используйте setRepeating(int, long, long, PendingIntent) вместо этого.

В итоге не очень понятно. В документах только говорится, что сигнал тревоги «может варьироваться». Однако вам должно быть важно знать, что первый триггер может не срабатывать в течение почти полного интервала после этого времени.

person Felix    schedule 13.12.2010
comment
Я думаю, что услуга может быть больше, чем мне нужно для того, что я делаю, но ваш блог был хорошим чтением! Вы случайно не знаете, какое смещение обычно имеет SetInexactRepeating? - person ninjasense; 13.12.2010
comment
Я отредактировал свой ответ, чтобы объяснить проблему setInexactRepeating. - person Felix; 14.12.2010
comment
в качестве бонуса вместо отмены перед установкой нового вы можете получить PendingIntent с PendingIntent.FLAG_CANCEL_CURRENT в качестве последнего параметра, который имеет тот же эффект. - person nsL; 18.10.2013
comment
У меня есть вопрос о PendingIntent. предположим, что другие классы используют alarmManager с теми же кодами запросов, но с другими намерениями, которые используются для других служб/действий/получателей. будет ли это проблемой? коды запросов должны быть уникальными для всего приложения? что на самом деле происходит в таком случае? - person android developer; 02.02.2014
comment
@Felix, я читаю ваш блог и делаю то же самое, но вместо повторяющейся задержки я использую календарь! но каждый раз, когда я открываю приложение, срабатывает будильник! stackoverflow.com/questions/33981142 / - person user2549089; 29.11.2015
comment
если приложение принудительно закрыто или удалено из последнего приложения, будет ли оно запускать этот диспетчер повторяющихся сигналов тревоги? во многих ответах утверждается, что это произойдет, но я не нашел ни малейшего понятия, как это сделать, и после многих попыток это все еще не сработало. - person KOTIOS; 19.01.2016
comment
@Felix: Если вы отмените/восстановите будильник (в onResume, как в вашем руководстве), и первое срабатывание будильника может быть отложено до одного интервала, означает ли это, что он будет запускаться каждый другой день , когда установлен дневной интервал? - person BeniBela; 29.08.2017

Это работает, это будет стрелять по тревоге каждые 5 секунд

private void setRecurringAlarm() {

        Logger.d(IConstants.DEBUGTAG, "Setting Recurring Alarm");

        Calendar updateTime = Calendar.getInstance();

        updateTime.set(Calendar.SECOND, 5);

        Intent alarmIntent = new Intent(this, AlarmReceiver.class);
        PendingIntent recurringDownload = PendingIntent.getBroadcast(this, 0, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        AlarmManager alarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarms.cancel(recurringDownload);
        alarms.setInexactRepeating(AlarmManager.RTC_WAKEUP, updateTime.getTimeInMillis(), 1000 * 5, recurringDownload); //will run it after every 5 seconds.
    }
person AZ_    schedule 24.07.2013
comment
в чем разница между setInexactRepeating и setRepeating? - person Raju yourPepe; 23.09.2013
comment
Запланируйте повторяющийся сигнал тревоги с неточными требованиями к времени срабатывания; например, будильник, который повторяется каждый час, но не обязательно в начале каждого часа. Эти тревоги более энергоэффективны, чем строгие повторения, предоставляемые setRepeating(int, long, long, PendingIntent), поскольку система может регулировать фазу тревог, чтобы они срабатывали одновременно, избегая пробуждения устройства из спящего режима больше, чем это необходимо. - person AZ_; 23.09.2013