Выполнение задачи в определенное время с использованием postDelayed

77
8

Я хотел бы запустить задачу в определенное время. Для этого я использую метод runnable и postDelayed следующим образом:


private Runnable mLaunchTask = new Runnable() {
public void run() {

try {
MY TASK
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

}
};


В моем коде я использую mLunchTask следующим образом:


mHandler = new Handler();
mHandler.postDelayed(mLaunchTask, myDelay*1000);

и myDelay вычисляется следующим образом:


s  = DateFormat.format("hh:mm:ss aaa", d.getTime());
cTime = s.toString(); // current Time
ch = Integer.parseInt(cTime.substring(0,2)); // current hour
cm = Integer.parseInt(cTime.substring(3,5)); // current minute
cs = Integer.parseInt(cTime.substring(6,8)); // current second
if (cTime.substring(9,11).equalsIgnoreCase("pm") && (ch<12) ) ch = ch+12;
myDelay=(desiredHour-ch)*3600+(desiredMinute-cm)*60 - cs;
if (myDelay<0) myDelay = 0;

и desiredHour и desiredMinute устанавливаются пользователем. Ожидается, что MY TASK начинается с desiredHour и desiredMinute и 0 секунд.
Однако "MY TASK начинается с задержки в несколько секунд, которая выглядит как случайная.


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


Спасибо

спросил(а) 2021-01-25T20:31:38+03:00 4 месяца, 4 недели назад
1
Решение
98

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


Calendar calendar = Calendar.getInstance();
long currentTimestamp = calendar.getTimeInMillis();
calendar.set(Calendar.HOUR_OF_DAY, desiredHour);
calendar.set(Calendar.MINUTE, desiredMinute);
calendar.set(Calendar.SECOND, 0);
long diffTimestamp = calendar.getTimeInMillis() - currentTimestamp;
long myDelay = (diffTimestamp < 0 ? 0 : diffTimestamp);

Теперь у вас есть задержка в миллисекундах и вы можете запустить обработчик:


new Handler().postDelayed(mLaunchTask, myDelay);

В моем тесте следующие runnable журналы в нужное время без задержки.


private Runnable mLaunchTask = new Runnable() {
public void run() {
Calendar calendar = Calendar.getInstance();
Log.d("test", "started at "
+ calendar.get(Calendar.HOUR_OF_DAY) + " "
+ calendar.get(Calendar.MINUTE) + " "
+ calendar.get(Calendar.SECOND)
);
}
};

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


Может ли альтернатива AlarmManager?

ответил(а) 2021-01-25T20:31:38+03:00 4 месяца, 4 недели назад
46

Основываясь на моем опыте и чтении документации, postDelayed основан на времени безотказной работы, а не в режиме реального времени. Если телефон переходит в глубокий сон, это может привести к тому, что в реальном времени пройдет без увеличения времени нарастания. Это означает, что ваша задача начнется позже, чем нужно.


Обработчик действительно, похоже, предназначен для обновления графического интерфейса в активной деятельности, а не для планирования задач в будущем. Как сказал скупщик, AlarmManager, вероятно, лучший выбор.

ответил(а) 2021-01-25T20:31:38+03:00 4 месяца, 4 недели назад
45

Ответ Налибы не совсем корректен.


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

"Для обработчика используются два основных вида использования: (1) , чтобы планировать сообщения и исполняемые файлы, которые должны выполняться как некоторая точка в будущем; (2), чтобы поставить в очередь действие, которое будет выполняться в другой поток, чем ваш собственный."


Нет никакой информации о поведении приложения, когда система переходит в спящий режим, и эта проблема должна быть протестирована перед публикацией дополнительной информации.

ответил(а) 2021-01-25T20:31:38+03:00 4 месяца, 4 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема