3

У меня есть приложение, которое периодически посылает сигналы тревоги каждый день недели, с помощью метода setRepeating из AlarmManager:Android - Избегайте тревожный сигнал, когда пользователь изменяет дату/время

Intent intent = new Intent(context, AlarmReceiver.class); 
    intent.putExtra(INTENT_TAG_ALERT_ID, lastAlertId.getId()+""); 
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, idRandom, intent, Intent.FLAG_ACTIVITY_NEW_TASK); 
    AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); 
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cDate.getTimeInMillis(), ((AlarmManager.INTERVAL_DAY)*7), pendingIntent); 

А затем получить сигнал тревоги на моем AlarmReceiver определяется на манифест как приемник:

<receiver 
     android:name=".manager.alarm.AlarmReceiver" 
     android:exported="true"> 
    </receiver> 

проблема заключается в том, когда пользователь изменяет дату/время со своего телефона в течение дня или 2 в будущем, я получаю несколько звонков от приемника (в зависимости от количества выбранных дней). Поскольку я использую метод setRepeating, я не могу подтвердить, был ли отправлен сигнал тревоги в нужное время.

Я знаю, что это обычная процедура, как описано здесь: "A trigger time. If the trigger time you specify is in the past, the alarm triggers immediately.", но я хочу предотвратить это.

Я думал поставить слушателя, чтобы узнать, когда пользователь изменяет дату и время его телефон, чтобы запланированную все сигналы тревоги, а затем планировать их снова, как вы можете увидеть ниже:

public class DateTimeChangedBroadcastReceiver extends BroadcastReceiver { 
@Override 
public void onReceive(Context context, Intent intent) { 
    String action = intent.getAction(); 
    if (action.equals(Intent.ACTION_TIMEZONE_CHANGED) || action.equals(Intent.ACTION_TIME_CHANGED) || action.equals(Intent.ACTION_DATE_CHANGED)) { 
     AlarmScheduler.unscheduleAllAlarms(); 
     //and then 
     AlarmScheduler.scheduleAllAlarms(); 
    } 
} 
} 

И манифест:

 <receiver android:name=".manager.alarm.DateTimeChangedBroadcastReceiver" 
     android:priority="1000"> 
     <intent-filter> 
      <action android:name="android.intent.ACTION_TIMEZONE_CHANGED"/> 
     </intent-filter> 
     <intent-filter> 
      <action android:name="android.intent.ACTION_TIME"/> 
     </intent-filter> 
     <intent-filter> 
      <action android:name="android.intent.action.DATE_CHANGED" /> 
     </intent-filter> 
     <intent-filter> 
      <action android:name="android.intent.action.TIME_SET"/> 
     </intent-filter> 
     <intent-filter> 
      <action android:name="android.intent.action.ACTION_TIME_CHANGED"/> 
     </intent-filter> 

    </receiver> 

Но в этом решении, получатель изменения времени приходит после приемника от тревоги, поэтому он не служит мне больше ...

есть способ выбрать порядок моих приемников?

Есть ли лучший способ сделать это?

Я также хочу положить слушателя в часы, чтобы сохранить его. если пользователь меняет час, я должен только проверять разницу ... но я считаю, что могу получить лучший способ сделать это (предпочтительнее не включать другого слушателя в приложение)

ответ

0

Это не является идеальным решением, больше как обходной путь, но это делает трюк ...

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

public boolean isReceiveAlarmValid (AlertData alertData, AlarmData alarmData){ 
    if ((alertData != null) && (alarmData != null)) { 

     Calendar caInitialDate = Calendar.getInstance(); 
     //Set beginning of counting to alarm starting date 
     caInitialDate.set(Calendar.YEAR, alarmData.getTimeAlarmYear()); 
     caInitialDate.set(Calendar.MONTH, (alarmData.getTimeAlarmMonth()) - 1); 
     caInitialDate.set(Calendar.DAY_OF_MONTH, alarmData.getTimeAlarmDay()); 
     caInitialDate.set(Calendar.HOUR_OF_DAY, alarmData.getTimeAlarmHour()); 
     caInitialDate.set(Calendar.MINUTE, alarmData.getTimeAlarmMinute()); 
     caInitialDate.set(Calendar.SECOND, alarmData.getTimeAlarmSeconds()); 

     caInitialDate.add(Calendar.MINUTE, alertData.getRescheduleCounter() * GeneralData.getInstance().getAlarmReschedulePeriodicity()); 

     alarmData.setTimeAlarm(GlobalFunctions.generateStringDateFromCalendar(caInitialDate)); 

     //Initialization 
     int sizeAux = 7; 
     String auxDateComp = ""; 
     String auxDate = null; 
     String[] auxDateArray = new String[7]; 

     Calendar calendar = Calendar.getInstance(); 
     int todayDay = calendar.get(Calendar.DAY_OF_WEEK); 

     if (Consts.FREQUENCY_ONCE == alarmData.getAlarmFrequency()) { 
      //Alarm Once 
      auxDate = String.format(Locale.getDefault(), "%04d", alarmData.getTimeAlarmYear()) + "-" + 
        String.format(Locale.getDefault(), "%02d", alarmData.getTimeAlarmMonth()) + "-" + 
        String.format(Locale.getDefault(), "%02d", alarmData.getTimeAlarmDay()) + " " + 
        String.format(Locale.getDefault(), "%02d", alarmData.getTimeAlarmHour()) + ":" + 
        String.format(Locale.getDefault(), "%02d", alarmData.getTimeAlarmMinute()) + ":00"; 

      auxDateComp = auxDate; 

     } else if (Consts.FREQUENCY_DAILY == alarmData.getAlarmFrequency()) { 
      //Alarm Daily 

      //Cycle to know what a specific day we are gonna compare on the week 
      dayCicle: 
      for (int i = 0; i < 7; i++) { 

       int auxDay = todayDay + i; 
       if (auxDay > 7) 
        auxDay = auxDay - 7; 

       auxDateArray = new String[7]; 

       if (((alarmData.isRepeatMonday()) && (auxDay == dayMon)) || 
         ((alarmData.isRepeatTuesday()) && (auxDay == dayTue)) || 
         ((alarmData.isRepeatWednesday()) && (auxDay == dayWed)) || 
         ((alarmData.isRepeatThursday()) && (auxDay == dayThu)) || 
         ((alarmData.isRepeatFriday()) && (auxDay == dayFri)) || 
         ((alarmData.isRepeatSaturday()) && (auxDay == daySat)) || 
         ((alarmData.isRepeatSunday()) && (auxDay == daySun))) { 

        int dayPeriodic = auxDay; 
        boolean[] isRepeatElements = new boolean[7]; 
        isRepeatElements[Consts.ANDROID_DAY_OF_THE_WEEK_SUNDAY] = alarmData.isRepeatSunday(); 
        isRepeatElements[Consts.ANDROID_DAY_OF_THE_WEEK_MONDAY] = alarmData.isRepeatMonday(); 
        isRepeatElements[Consts.ANDROID_DAY_OF_THE_WEEK_TUESDAY] = alarmData.isRepeatTuesday(); 
        isRepeatElements[Consts.ANDROID_DAY_OF_THE_WEEK_WEDNESDAY] = alarmData.isRepeatWednesday(); 
        isRepeatElements[Consts.ANDROID_DAY_OF_THE_WEEK_THURSDAY] = alarmData.isRepeatThursday(); 
        isRepeatElements[Consts.ANDROID_DAY_OF_THE_WEEK_FRIDAY] = alarmData.isRepeatFriday(); 
        isRepeatElements[Consts.ANDROID_DAY_OF_THE_WEEK_SATURDAY] = alarmData.isRepeatSaturday(); 


        int daysCount = i; 

        Calendar caTimeStartAlarm = Calendar.getInstance(); 
        Calendar caNow = Calendar.getInstance(); 
        //Set beginning of counting to alarm starting date 
        caTimeStartAlarm.set(Calendar.YEAR, alarmData.getTimeAlarmYear()); 
        caTimeStartAlarm.set(Calendar.MONTH, (alarmData.getTimeAlarmMonth()) - 1); 
        caTimeStartAlarm.set(Calendar.DAY_OF_MONTH, alarmData.getTimeAlarmDay()); 
        caTimeStartAlarm.set(Calendar.HOUR_OF_DAY, alarmData.getTimeAlarmHour()); 
        caTimeStartAlarm.set(Calendar.MINUTE, alarmData.getTimeAlarmMinute()); 
        caTimeStartAlarm.set(Calendar.SECOND, alarmData.getTimeAlarmSeconds()); 

        Calendar calInitial = null; 

        //If time now is after starting time, the base date is the now date 
        if (caTimeStartAlarm.after(caNow)) { 
         calInitial = (Calendar) caTimeStartAlarm.clone(); 
        } else { 
         calInitial = (Calendar) caNow.clone(); 
        } 


        //cycle that increase days adding to next alarms 
        for (int z = 0; z < 7; z++) { 

         //only chosen periodic daily days 
         if (isRepeatElements[dayPeriodic - 1]) { 

          Calendar caPossibleAlarm = (Calendar) calInitial.clone(); 
          //Add daily day 
          caPossibleAlarm.set(Calendar.DAY_OF_MONTH, caPossibleAlarm.get(Calendar.DAY_OF_MONTH) + daysCount); 
          caPossibleAlarm.set(Calendar.HOUR_OF_DAY, alarmData.getTimeAlarmHour()); 
          caPossibleAlarm.set(Calendar.MINUTE, alarmData.getTimeAlarmMinute()); 
          caPossibleAlarm.set(Calendar.SECOND, alarmData.getTimeAlarmSeconds()); 

          //add a few seconds of margin 
          caPossibleAlarm.add(Calendar.SECOND, ALARM_RECEIVE_TIME_MARGIN); 

          if (!(calInitial.after(caPossibleAlarm))) { 
           //If now is not after (before or equal) next alarm, then it can show 

           String yearAux = String.format(Locale.getDefault(), "%04d", caPossibleAlarm.get(Calendar.YEAR)); 
           String monthAux = String.format(Locale.getDefault(), "%02d", caPossibleAlarm.get(Calendar.MONTH) + 1); 
           String dayAux = String.format(Locale.getDefault(), "%02d", caPossibleAlarm.get(Calendar.DAY_OF_MONTH)); 
           auxDate = yearAux + "-" + monthAux + "-" + dayAux + " " + 
             String.format(Locale.getDefault(), "%02d", alarmData.getTimeAlarmHour()) + ":" + 
             String.format(Locale.getDefault(), "%02d", alarmData.getTimeAlarmMinute()) + ":00"; 

           auxDateComp = auxDate; 

          } 

         } 

         if ("".equals(auxDateComp)) { 

          dayPeriodic++; 
          if (dayPeriodic > 7) 
           dayPeriodic = dayPeriodic - 7; 

          daysCount++; 
         } else { 
          //it has found a value 
          break dayCicle; 
         } 
        } 

        break dayCicle; 

       } 

      } 

     } else { 
      //Periodic Weekly/Monthly 

      auxDate = String.format(Locale.getDefault(), "%04d", alarmData.getTimeAlarmYear()) + "-" + 
        String.format(Locale.getDefault(), "%02d", alarmData.getTimeAlarmMonth()) + "-" + 
        String.format(Locale.getDefault(), "%02d", alarmData.getTimeAlarmDay()) + " " + 
        String.format(Locale.getDefault(), "%02d", alarmData.getTimeAlarmHour()) + ":" + 
        String.format(Locale.getDefault(), "%02d", alarmData.getTimeAlarmMinute()) + ":00"; 

      Calendar caNow = Calendar.getInstance(); 
      Calendar caAlarmTime = Calendar.getInstance(); 

      caAlarmTime.set(Calendar.YEAR, alarmData.getTimeAlarmYear()); 
      caAlarmTime.set(Calendar.MONTH, alarmData.getTimeAlarmMonth()); 
      caAlarmTime.set(Calendar.DAY_OF_MONTH, alarmData.getTimeAlarmDay()); 
      caAlarmTime.set(Calendar.HOUR_OF_DAY, alarmData.getTimeAlarmHour()); 
      caAlarmTime.set(Calendar.MINUTE, alarmData.getTimeAlarmMinute()); 

      if (caAlarmTime.after(caNow)) { 
       //next date is from the alarm 
       auxDate = String.format(Locale.getDefault(), "%04d", alarmData.getTimeAlarmYear()) + "-" + 
         String.format(Locale.getDefault(), "%02d", alarmData.getTimeAlarmMonth()) + "-" + 
         String.format(Locale.getDefault(), "%02d", alarmData.getTimeAlarmDay()) + " " + 
         String.format(Locale.getDefault(), "%02d", alarmData.getTimeAlarmHour()) + ":" + 
         String.format(Locale.getDefault(), "%02d", alarmData.getTimeAlarmMinute()) + ":00"; 
      } else { 
       //It needs to check when is the next possible alarm 
       boolean foundNextDate = false; 

       foundNextDateCycle: 
       while (foundNextDate == false) { 

        if (Consts.FREQUENCY_WEEKLY == alarmData.getAlarmFrequency()) 
         caAlarmTime.add(Calendar.DAY_OF_MONTH, 7); 
        else if (Consts.FREQUENCY_MONTHLY == alarmData.getAlarmFrequency()) 
         caAlarmTime.add(Calendar.MONTH, 1); 
        else 
         caAlarmTime.add(Calendar.YEAR, 1); 

        try { 
         if (caAlarmTime.after(caNow)) 
          foundNextDate = true; 
        } catch (Exception e) { 
         break foundNextDateCycle; 
        } 

       } 


       auxDate = String.format(Locale.getDefault(), "%04d", caAlarmTime.get(Calendar.YEAR)) + "-" + 
         String.format(Locale.getDefault(), "%02d", caAlarmTime.get(Calendar.MONTH) + 1) + "-" + 
         String.format(Locale.getDefault(), "%02d", caAlarmTime.get(Calendar.DAY_OF_MONTH)) + " " + 
         String.format(Locale.getDefault(), "%02d", caAlarmTime.get(Calendar.HOUR_OF_DAY)) + ":" + 
         String.format(Locale.getDefault(), "%02d", caAlarmTime.get(Calendar.MINUTE)) + ":00"; 

      } 

      auxDateComp = auxDate; 
     } 




     if("".equals(auxDateComp)) 
      return false; 


     Calendar calendarNow = Calendar.getInstance(); 
     Calendar calendarBegin = Calendar.getInstance(); 
     Calendar calendarFisnish = Calendar.getInstance(); 


     int marginMinutes = 1; //1 minute of margin 


     calendarBegin.set(Calendar.YEAR, Integer.parseInt(GlobalFunctions.formateDateFromString("yyyy-MM-dd HH:mm:ss", "yyyy", auxDateComp))); 
     calendarBegin.set(Calendar.MONTH, (Integer.parseInt(GlobalFunctions.formateDateFromString("yyyy-MM-dd HH:mm:ss", "MM", auxDateComp))) - 1); 
     calendarBegin.set(Calendar.DAY_OF_MONTH, Integer.parseInt(GlobalFunctions.formateDateFromString("yyyy-MM-dd HH:mm:ss", "dd", auxDateComp))); 
     calendarBegin.set(Calendar.HOUR_OF_DAY, Integer.parseInt(GlobalFunctions.formateDateFromString("yyyy-MM-dd HH:mm:ss", "HH", auxDateComp))); 
     calendarBegin.set(Calendar.MINUTE, Integer.parseInt(GlobalFunctions.formateDateFromString("yyyy-MM-dd HH:mm:ss", "mm", auxDateComp))); 
     calendarBegin.set(Calendar.SECOND, Integer.parseInt(GlobalFunctions.formateDateFromString("yyyy-MM-dd HH:mm:ss", "ss", auxDateComp))); 


     calendarFisnish = (Calendar) calendarBegin.clone(); 

     calendarBegin.set(Calendar.MINUTE, calendarBegin.get(Calendar.MINUTE) - marginMinutes); 
     calendarFisnish.set(Calendar.MINUTE, calendarFisnish.get(Calendar.MINUTE) + marginMinutes); 

     if (calendarNow.after(calendarBegin) && calendarNow.before(calendarFisnish)) { 
      Log.e(GlobalFunctions.getTag(), "Gonna show alarm!"); 
      return true; 
     } else { 
      Log.e(GlobalFunctions.getTag(), "NOT Gonna show alarm!"); 
      return false; 
     } 


    } else{ 
     //alarmData or alertData are NULL 
     return false; 
    } 

} 

После этого я также проверить, если мой массив принятых сигналов тревоги, имеет значение с одинаковыми идентификаторами, а затем показываю только один из них (просто чтобы убедиться, что нет никаких остатков)

Я попытался установить час спустя 2 года, и это довольно быстро (по крайней мере, на моем устройстве)

Опять же, это не является идеальным решением, если кто-то найти лучшее решение, пожалуйста, напишите его

1

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

AlarmReceiver.java

@Override 
public void onReceive(Context context, Intent intent) { 


    //Handle the logics here. 
    //This function is called every time alarm repeats. 
    //So simply find out if you need an alarm right now and pop alarm. 
} 

XML

<receiver android:name=".manager.alarm.AlarmReceiver" 
     android:exported="true"> 
     <intent-filter> 
      <action android:name="android.intent.ACTION_TIMEZONE_CHANGED"/> 
     </intent-filter> 
     <intent-filter> 
      <action android:name="android.intent.ACTION_TIME"/> 
     </intent-filter> 
     <intent-filter> 
      <action android:name="android.intent.action.DATE_CHANGED" /> 
     </intent-filter> 
     <intent-filter> 
      <action android:name="android.intent.action.TIME_SET"/> 
     </intent-filter> 
     <intent-filter> 
      <action android:name="android.intent.action.ACTION_TIME_CHANGED"/> 
     </intent-filter> 

    </receiver> 

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

Надеюсь, это поможет.

+1

I не знаю, как я могу это знать ... Я использовал setRepeati ng, где я знаю только, когда будильник был создан в первый раз ... Я могу узнать только час, который должен посылать будильник, а не день ... и если будильник повторяется в течение месяца, как я могу знать если пользователь набирает 5 дней или всего 1? Я могу сделать некоторые расчеты, основанные на создании тревоги, и проверить, действительно ли время срабатывания тревоги было фактически допустимым сигналом тревоги, но это может быть связано с множеством вычислений, если тревога была впервые создана год или 2 назад ... Я думаю, что это неправильно? – slyzer

+0

Предположим, я поставил будильник на 2 марта 2016 года. Затем я изменил системное время на 2 марта 2016 года. Тогда я ожидаю, что будильник погаснет в данный момент. Поэтому вам не нужно выполнять сложные вычисления, чтобы изменить это поведение. Но убедитесь, что время тревоги может быть вручную изменено пользователем. Также на ui должно отображаться следующее время будильника. – Cijo

+1

Я не понял ваш пример ... Исправить пример, у меня есть будильник, который был установлен 1 год назад, который повторяется каждый день ... и когда я получаю звонок от «AlarmReceiver», я знаю только, когда будильник был создан, что означает, что я знаю только дату и час (первого создания) ... Поскольку сигналы тревоги должны срабатывать каждый день в одно и то же время, я могу действовать, если час находится в допустимом периоде тревоги .. но если пользователь меняет время в течение этого действительного периода, этот процесс не работает. Если вы можете проверить срабатывающий сигнал тревоги внутри приемника, какие условия я должен выполнить? – slyzer

Смежные вопросы