Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding multiple reminders causes them to trigger at the same time

I include here the full problem description because I'm not exactly sure if the logic behind the solution is even correct, but I am pretty sure that it has to do with the way I'm setting the alarms themselves that's causing this inaccuracy, or just sometimes pure fault (alarms don't trigger at all).


A user can add a new medication from a list of medications.

Screen 1

When a certain medication is found, clicking on it will show this screen http://imgur.com/nLC9gTG

That screen contains the Medication's name and under the "Posology" title (the green bar) is where the reminders for that Medication can be added.

Forget the "Units" field.

The "Frequency" field accepts a number and the label to the right of the "Frequency" field is clickable, it causes a dropdown menu to appear, from which the user can select "times for day" or "times per week".

The "Days of week" label (the label is empty in the screenshot) is also clickable, it presents the user with a dropdown menu from which the user can select multiple days from the days of a week.

The "Treatment Duration" field accepts a number and the label to the right of the "Treatment Duration" field will reflect the user's choice of "Frequency" (if it's "times per week" then that label will say "weeks", if it's "times per month" then that label will say "months").


Screen 2

In this second screenshot http://imgur.com/AcUmlHH -- There is a Switch which allows the user to enable reminders for this Medication (item, instance, etc.) that he's attempting to add.

If the "Frequency" field above has a number greater than 0 (2, for example), then the reminders Switch will create a list of Reminder fields which it will show just underneath the "Get Notifications" green bar.

When the user finally presses on "Add Medication", a new Medication object will be created in the database, along with the "Frequency" (number of reminders) that the user has chosen to add for this Medication object.


Create a Medication table:

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

Create a MedicationReminder table:

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

Upon creating this new Medication object:

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

assignForeignCollectionToParentObject(medication);

assignForeignCollectionToParentObject(Medication)

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);
          }
        }
      }
    }
}

The problem is when the medication reminders are added, they are always triggered shortly after being added, and all at the same time.

Say I select Frequency 2 for Saturday and Friday with a treatment duration of 1 week. This means that there will be a total of 4 reminders being added, 2 on Friday and 2 on Saturday.

When I do this, and it happens to be a Saturday, the alarms trigger at the same time together, for Saturday.

What's wrong?

like image 565
Odaym Avatar asked Jan 23 '17 13:01

Odaym


2 Answers

When you do this:

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

The results are unpredictable. If the current day is a Monday and you call set(Calendar.DAY_OF_WEEK) with Calendar.THURSDAY, should the date be changed to the previous Thursday? or the next Thursday? You don't know.

If your alarms are all going off immediately, this would indicate that changing the DAY_OF_WEEK is causing the calendar to go backwards instead of forwards. To verify that, after you set the DAY_OF_WEEK, call getTimeInMillis() and compare it against the current time. If it is smaller, then your calendar has gone back in time. To fix that, just add 7 days to the calendar.


Also, you are using this type of alarm: AlarmManager.ELAPSED_REALTIME_WAKEUP. This type takes a value that represents the amount of time that has passed since device boot.

However, you are using the RTC for the time value (ie: Calendar.getTimeInMillis()). These 2 values are incompatible. If you want to use the RTC, you need to use AlarmManager.RTC_WAKEUP.

like image 134
David Wasser Avatar answered Sep 23 '22 01:09

David Wasser


The problem is when the medication reminders are added, they are always triggered shortly after being added, and all at the same time.

That's because that's what you asked for. You are always reading the current time and setting it to the reminder time:

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

You never read the time provided by the user in this screen, i.e. the Calendar field of your reminder is never set. Here is your code:

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

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

  medReminder.setTotalTimesToTrigger(...);

You missed the line for actually setting the reminder time

like image 30
A.A. Avatar answered Sep 27 '22 01:09

A.A.