AlarmManager не срабатывает в нужное время

Я создаю приложение, которое использует TimePicker, в котором пользователь устанавливает время, когда они хотят, чтобы SMS было отправлено на указанный номер. У них также есть возможность нажать «Повторить», чтобы SMS-сообщения продолжали отправляться в одно и то же указанное время каждый день.

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

Вот код для получения времени из окна выбора времени и настройки AlarmManger:

Button setSchedule = (Button) setTimer.findViewById(R.id.setSchedule);
setSchedule.setText("Set");
setSchedule.setOnClickListener(new OnClickListener()
{

    @Override
    public void onClick(View v) 
    {
        hours = timePicker.getCurrentHour();
        minutes = timePicker.getCurrentMinute();
        minutesConv += hours * 60;
        minutes += minutesConv;
        seconds = minutes * 60;
        time = seconds * 1000;
        long currentTime = System.currentTimeMillis();

        CheckBox repeat = (CheckBox) setTimer.findViewById(R.id.repeat);

        Intent intentAlarm = new Intent(MainMenu.this, AlarmReceiver.class);
        PendingIntent pi = PendingIntent.getBroadcast(MainMenu.this, 0, intentAlarm, 0);
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

        if (repeat.isChecked())
        {
            alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, time - currentTime, AlarmManager.INTERVAL_DAY, pi);
        }//end if
        else
        {
            alarmManager.set(AlarmManager.RTC_WAKEUP,  time - currentTime,  PendingIntent.getBroadcast(MainMenu.this, 1, intentAlarm,
                    PendingIntent.FLAG_UPDATE_CURRENT));
        }//end else

        Toast.makeText(MainMenu.this, "Your message has been scheduled to be repeated at " +
                                    hours + ":" + minutes, Toast.LENGTH_SHORT).show();
        setTimer.dismiss();
    }//end onClick

});

РЕДАКТИРОВАТЬ:

Calendar cal = Calendar.getInstance();
Calendar current = Calendar.getInstance();
cal.set(0, 0, 0, timePicker.getCurrentHour(), timePicker.getCurrentMinute(), 00);
Toast.makeText(MainMenu.this, "time: " + cal.getTimeInMillis(), Toast.LENGTH_SHORT).show();
CheckBox repeat = (CheckBox) setTimer.findViewById(R.id.repeat);

Intent intentAlarm = new Intent(MainMenu.this, AlarmReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(MainMenu.this, 0, intentAlarm, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

if (repeat.isChecked())
{
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, pi);
}//end if
else
{
    alarmManager.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),  PendingIntent.getBroadcast(MainMenu.this, 1, intentAlarm,
                                        PendingIntent.FLAG_UPDATE_CURRENT));
}//end else

person sabo    schedule 27.01.2015    source источник
comment
Смотрите текущий ответ. time - currentTime обычно устанавливает будильник в прошлом, что приводит к немедленному срабатыванию будильника.   -  person iheanyi    schedule 27.01.2015
comment
@iheanyi А, это имеет смысл.   -  person sabo    schedule 27.01.2015
comment
Да. . . обратите внимание, (currentTime - время) было бы лучше (хотя все же неправильно). Вам просто повезло, что (time - currentTime) будет в прошлом, поскольку currentTime обычно довольно большое число. Кроме того, ваш расчет времени ошибочен. Он включает только минуты и секунды — не включает значение из часов.   -  person iheanyi    schedule 27.01.2015
comment
@iheanyi У меня есть значение для часов, я просто получаю текущие часы, установленные в TimePicker. Затем я конвертирую его в минуты.   -  person sabo    schedule 27.01.2015
comment
Похоже, вы обновили свой код, добавив строку, в которой говорится, что minute += minuteConv; Этого не было, когда я делал свой комментарий.   -  person iheanyi    schedule 28.01.2015
comment
@iheanyi Да, я обновил это. Будильник по-прежнему не срабатывает в нужное мне время.   -  person sabo    schedule 28.01.2015
comment
Я думаю, вы все еще не совсем понимаете. Вы устанавливаете будильник на текущее время + сколько миллисекунд в будущем вы хотите, чтобы ваш будильник срабатывал. Итак, если мой ЧЧММСС равен 01:10:15 - текущее время + время означает, что мой будильник сработает через 1 час, 10 минут и 15 секунд в будущем, а не в 01:10:15.   -  person iheanyi    schedule 28.01.2015
comment
Кроме того, у вашего кода все еще есть проблема со временем вычисления. У вас есть minuteConv += часы * 60. Тогда минуты += minuteConv и секунды = минуты * 60 Итак, скажем, часы = 1 и минуты = 5. Если minuteConv начинается с 0, minuteConv = 0 + 1*60. минуты обновляются до 5 + 60. Затем секунды до 65 * 60 = 3900. Затем, если вы снова установите таймер с точно такими же значениями, minuteConv = 3900 + 1 * 60 = 3960. минуты = 5 + 3960. Секунды = 3960 * 60 = 237600.   -  person iheanyi    schedule 28.01.2015
comment
@iheanyi Я знаю, что означает currentTime + time. Вот почему у меня есть это для моего метода set() в alarmManager. Он не срабатывает в нужное время, хотя логика, которую вы описываете, - это то, что я хочу. Я понимаю, что метод setRepeating() будет другим, но я выясню это, когда мы туда доберемся.   -  person sabo    schedule 28.01.2015
comment
Таким образом, время, которое выбирает пользователь, на самом деле зависит от того, насколько далеко в будущем он хочет, чтобы сработал будильник, а не КОГДА он хочет, чтобы он сработал правильно? Если нет, значит, вы неправильно устанавливаете время будильника.   -  person iheanyi    schedule 28.01.2015
comment
@iheanyi А, я тебя неправильно понимаю. Мне жаль. Я действительно хочу, чтобы будильник срабатывал в то время, когда пользователь устанавливает TimePicker, что заставляет меня думать, что мне нужно будет найти разницу между текущим временем и временем, которое они установили, поэтому я взял время - currentTime. Это не работает, поэтому я решил взять эту разницу и добавить ее обратно к текущему времени, чтобы получить время, которое мне нужно, но это избыточно, вычитание числа, а затем просто добавление обратно.   -  person sabo    schedule 28.01.2015
comment
Посмотрите на эту страницу. В разделе примеров RTC показано, как использовать объект календаря для вычисления правильного значения, если вы хотите установить будильник на определенное время. Тогда вам вообще не придется беспокоиться о каких-либо вычислениях: developer.android.com /training/scheduling/alarms.html   -  person iheanyi    schedule 28.01.2015


Ответы (2)


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

  1. Используйте метод в своем коде, где вы берете значение, введенное пользователем, и вычисляете дельту от currentTime в миллисекундах. Это полезно, когда пользователь указывает, что он хочет, чтобы тревога появлялась через X промежутка времени в будущем.
  2. Используйте календарный метод, описанный в примерах RTC здесь: https://developer.android.com/training/scheduling/alarms.html Это позволяет пользователям указывать время или полную дату для будильника, а вы просто получаете значение в миллисекундах непосредственно из объекта календаря.

Попробуйте это для своего календаря, чтобы установить один будильник:

hours = timePicker.getCurrentHour();
minutes = timePicker.getCurrentMinute();

Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(System.currentTimeMillis());
cal.set(Calendar.HOUR_OF_DAY, hours);
cal.set(Calendar.MINUTE, minutes);

alarmManager.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), PendingIntent.getBroadcast(MainMenu.this, 1, intentAlarm,
    PendingIntent.FLAG_UPDATE_CURRENT));

setTimeInMillis() обновляет объект календаря до текущей даты (так что год и все остальное настроено правильно). Затем вы устанавливаете календарь на будущее время в тот же день и передаете его диспетчеру сигналов тревоги.

person iheanyi    schedule 28.01.2015
comment
Используя объект календаря, я получаю отрицательное значение времени. Я добавил свой код с помощью Календаря - person sabo; 28.01.2015
comment
Я посмотрел, как, по-видимому, год будет неправильным и должен быть установлен на 1970 или что-то в этом роде, но я ничего не вижу ясного. Добавление 1970 или любого другого года, который я видел, не помогло. - person sabo; 28.01.2015
comment
Вы должны были использовать пример из ссылки, которую я вам дал. Он идеально соответствует тому, что вам нужно, и автоматически устанавливает год. - person iheanyi; 28.01.2015
comment
@saboehnke Я обновил свой ответ, чтобы вы могли использовать пример кода. Это плюс ссылка в ответе должны показать вам, как обращаться с повторяющимся случаем тревоги. - person iheanyi; 28.01.2015

Если я читаю документации правильно, параметр triggerAtMillis — это абсолютное, а не относительное время. Передача time + currentTime вместо time - currentTime должна быть в порядке.

person Joru    schedule 27.01.2015
comment
Пробовал, будильник вообще не срабатывает. Либо так, либо он уходит намного позже, чем должен. - person sabo; 27.01.2015
comment
Вы ставили будильник в ближайшее время? Проверьте, каковы все входы. Также проверьте код того, что вы ожидаете после срабатывания будильника, он не был включен в опубликованный вами бит. - person Joru; 27.01.2015
comment
Да, я бы установил это только на пару минут для тестирования. СМС-часть работает нормально. Сообщение отправляется просто отлично, его просто не происходит, когда я этого хочу. - person sabo; 27.01.2015
comment
Я чувствую, что что-то может быть не так с вашим обратным вызовом для будильника, возможно, просмотр https://developer.android.com/training/scheduling/alarms.html поможет вам найти проблему. Вы можете обновить свой исходный вопрос с помощью этого кода, который также реагирует на срабатывание будильника. - person Joru; 27.01.2015
comment
Это документация, которую я использовал для этого в первую очередь. Я посмотрел повсюду, но, похоже, ничто не объясняет мою проблему. - person sabo; 27.01.2015
comment
Я заметил, что сообщение отправляется, когда я тестирую, примерно через 15 минут. Я не знаю, как я использую время неправильно, хотя. - person sabo; 27.01.2015
comment
Вероятно, вы неправильно устанавливаете время будильника. Вам нужно добавить к currentTime количество миллисекунд в будущем, когда вы хотите, чтобы будильник срабатывал. - person iheanyi; 28.01.2015