添加多个提醒会导致它们同时触发

时间:2017-01-23 13:03:56

标签: android calendar alarmmanager alarms

我在这里包含完整的问题描述,因为我不确定解决方案背后的逻辑是否正确,但我很确定它与我设置警报的方式有关他们自己导致了这种不准确,或者只是有时是纯粹的错误(警报根本不会触发)。

用户可以从药物清单中添加新的药物。

屏幕1

找到某种药物后,点击它会显示此屏幕http://imgur.com/nLC9gTG

该屏幕包含Medication的名称,并在" Posology"标题(绿色条)是可以添加该药物的提醒的地方。

忘掉"单位"字段。

"频率"字段接受一个数字和标签右边的"频率"字段是可点击的,它会显示一个下拉菜单,用户可以从中选择"时间和#34;或者"每周一次"。

"星期几"标签(屏幕截图中的标签为空)也是可点击的,它向用户显示一个下拉菜单,用户可以从中选择一周中的几天。

治疗持续时间"字段接受一个数字和标签右边的#34;治疗持续时间"字段将反映用户对频率"频率" (如果是""每周时间"那么该标签会说"周",如果它"每个月"那么该标签会说"月")。

屏幕2

在第二个屏幕截图http://imgur.com/AcUmlHH中 - 有一个开关允许用户启用他正在尝试添加的此药物(项目,实例等)的提醒。

如果"频率"上面的字段有一个大于0的数字(例如2),然后提醒开关将创建一个提醒字段列表,它将显示在"获取通知"绿色酒吧。

当用户最终按下"添加药物"时,将在数据库中创建一个新的药物对象,以及"频率" (用户已选择为此Medication对象添加的提醒数量。)

  

创建一个Medication表:

id
name
description
dosage
frequency
frequencyType
treatmentDuration
ForeignCollection<MedicationReminder>
ArrayList<DayChoice> (DayChoice is a class with "Day Name" and "Selected")
when
whenString
units
unitForm
remarks
remindersEnabled
  

创建MedicationReminder表:

Medication (foreign key for the Medication table)
Calendar
int[] days_of_week
totalTimesToTrigger
  

创建此新的Medication对象后:

Medication medication = new Medication();
medication.setFrequency()
medication.setName().setDosage().setRemindersEnabled()....

assignForeignCollectionToParentObject(medication);
  

assignForeignCollectionToParentObject(药物)

private void assignForeignCollectionToParentObject(Medication medicationObject) {
    medicationDAO.assignEmptyForeignCollection(medicationObject, "medicationReminders");

    MedicationRemindersRecyclerAdapter adapter =
        (MedicationRemindersRecyclerAdapter) remindersRecyclerView.getAdapter();

    //Clear previous reminders
    medicationObject.getMedicationReminders().clear();

    for (int i = 0; i < adapter.getItemCount(); i++) {
      int realDaysSelected = 0;

      MedicationReminder medReminder = adapter.getItem(i);
      medReminder.setMedication(medicationObject);
      medReminder.setDays_of_week(daysOfWeekArray);

      //These days are populated when the user selected them from the "Days of Week" clickable label
      for (int aDaysOfWeekArray : daysOfWeekArray) {
        if (aDaysOfWeekArray != 0) realDaysSelected++;
      }

      medReminder.setTotalTimesToTrigger(
          Integer.parseInt(treatmentDurationET.getText().toString()) * realDaysSelected);
      medicationObject.getMedicationReminders().add(medReminder);
    }

    setupMedicationReminders(medicationObject.getMedicationReminders().iterator());
}
  

setupMedicationReminders()

public void setupMedicationReminders(Iterator<MedicationReminder> medicationRemindersIterator) {
    PendingIntent pendingIntent;
    AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

    while (medicationRemindersIterator.hasNext()) {
      MedicationReminder medReminder = medicationRemindersIterator.next();

      for (int i = 0; i < medReminder.getDays_of_week().length; i++) {

        int dayChosen = medReminder.getDays_of_week()[i];

        if (dayChosen != 0) {
          medReminder.getAlarmTime().setTimeInMillis(System.currentTimeMillis());
          medReminder.getAlarmTime().set(Calendar.DAY_OF_WEEK, dayChosen);

          Intent intent = new Intent(AddExistingMedicationActivity.this, AlarmReceiver.class);
          intent.putExtra(Constants.EXTRAS_ALARM_TYPE, "medications");
          intent.putExtra(Constants.EXTRAS_MEDICATION_REMINDER_ITEM, (Parcelable) medReminder);

          pendingIntent = PendingIntent.getBroadcast(this, medReminder.getId(), intent,
              PendingIntent.FLAG_UPDATE_CURRENT);

          int ALARM_TYPE = AlarmManager.ELAPSED_REALTIME_WAKEUP;

          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            am.setExactAndAllowWhileIdle(ALARM_TYPE, medReminder.getAlarmTime().getTimeInMillis(),
                pendingIntent);
          } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            am.setExact(ALARM_TYPE, medReminder.getAlarmTime().getTimeInMillis(), pendingIntent);
          } else {
            am.set(ALARM_TYPE, medReminder.getAlarmTime().getTimeInMillis(), pendingIntent);
          }
        }
      }
    }
}

问题是当添加药物提醒时,它们总是在被添加后不久被触发,并且全部同时被触发。

假设我选择星期六和星期五的频率2,治疗时间为1周。这意味着将添加总共4个提醒,周五为2,周六为2。

当我这样做时,恰好是星期六,警报会在星期六同时触发。

出了什么问题?

3 个答案:

答案 0 :(得分:3)

执行此操作时:

medReminder.getAlarmTime().setTimeInMillis(System.currentTimeMillis());
medReminder.getAlarmTime().set(Calendar.DAY_OF_WEEK, dayChosen);

结果无法预测。如果当天是星期一,并且您使用set(Calendar.DAY_OF_WEEK)致电Calendar.THURSDAY,那么日期是否应更改为上一个星期四?还是下个星期四?你不知道。

如果您的闹钟立即全部响起,则表示更改DAY_OF_WEEK会导致日历倒退而不是转发。要在设置DAY_OF_WEEK后验证,请调用getTimeInMillis()并将其与当前时间进行比较。如果它更小,那么您的日历已经回溯。要解决此问题,只需在日历中添加7天。

此外,您正在使用此类警报:AlarmManager.ELAPSED_REALTIME_WAKEUP。此类型采用一个值,表示自设备启动以来经过的时间量。

但是,您使用RTC作为时间值(即:Calendar.getTimeInMillis())。这两个值不兼容。如果您想使用RTC,则需要使用AlarmManager.RTC_WAKEUP

答案 1 :(得分:2)

  

问题是当添加药物提醒时,它们总是在被添加后不久被触发,并且全部同时被触发。

那是因为那就是你要求的。您总是在阅读当前时间并将其设置为提醒时间:

medReminder.getAlarmTime().setTimeInMillis(System.currentTimeMillis());

您从未在this screen中阅读用户提供的时间,即您的提醒的Calendar字段永远不会设置。这是你的代码:

  MedicationReminder medReminder = adapter.getItem(i);
  medReminder.setMedication(medicationObject);
  medReminder.setDays_of_week(daysOfWeekArray);

  for (int aDaysOfWeekArray : daysOfWeekArray) {
    if (aDaysOfWeekArray != 0) realDaysSelected++;
  }

  medReminder.setTotalTimesToTrigger(...);

您错过了实际设置提醒时间的行

答案 2 :(得分:0)

这可能不是你问题的答案,但恕我直言,你应该考虑这个。

我认为这是糟糕的用户体验。此应用程序的用户可能会仅根据时间(没有日期)来混淆提醒的时间。因此,最好在用户能够编辑的每个提醒旁边添加完整日期。当您第一次生成它们时,您可以按正确的顺序设置它们。

Reminder 1:  2/2/2017 13:04

Reminder 2:  9/2/2017 13:04

Reminder 3: 16/2/2017 13:04

Reminder 4: 25/2/2017 13:04

这也会更好地反映现实世界。让我们考虑一下这个用例:用户有他的手机,但他忘记了用药。他不能在正确的时间接受它,所以他稍后会采取它(甚至可能是tommorow)。这将搞乱计划,但在这种情况下,他可以将日期编辑为他实际服用药物的日期。然后在他编辑的所有提醒之后根据times_per_week,times_per_month调整所有提醒的日期和时间。他不应该把它们改成过去的日期。

Reminder 1:  2/2/2017 13:04 // He took medication on time

Reminder 2:  9/2/2017 13:04 // He missed this one and changed to date bellow
            10/2/2017 12:22 // This is when he actually took the medication

Reminder 3: 16/2/2017 13:04 // This is no longer valid
            17/2/2017 12:22  // You adjust reminder to this date and time

Reminder 4: 25/2/2017 13:04 // This is no longer valid
            26/2/2017 12:22 // You adjust reminder to this date and time

用户必须仍限于每个提醒的特定日期范围。你不能让他挑选任何约会。这是基于他的计划设置和当前日期,但我不想进入。这需要做很多工作。

如果将这些更改写入数据库,则不应丢失数据。您可以稍后为您的应用程序添加一项功能:报告用户迟到的次数与用户按时服用药物的次数。这对移动应用程序来说是个不错的小功能。