setAlarmClock() срабатывает слишком поздно в режиме ожидания
У меня так много проблем, чтобы заставить мой радиобудильник работать так, как задумано, и я прочитал здесь много тем на эту тему, но, к сожалению, никто не помог мне.
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent penInt = PendingIntent.getBroadcast(this, intentId, intent, 0);
Этот метод разграничения уровней API, который я нашел здесь в stackru, и поместил его в мой calcNextAlarm()
Функция (плюс некоторые сообщения журнала для отладки) для правильной установки будильника независимо от того, какой API используется на устройстве:
// problems in doze mode api 23+
if (Build.VERSION.SDK_INT >= 23) {
if (testMode) Log.d("Ben", "setAlarmClock() - API 23+");
am.setAlarmClock(new AlarmManager.AlarmClockInfo(alarmTimeInMillis, penInt), penInt);
}
else if (Build.VERSION.SDK_INT >= 19) {
// Wakes up the device in Idle Mode
if (testMode) Log.d("Ben", "setExact() - API >= 19 && API < 23");
am.setExact(AlarmManager.RTC_WAKEUP, alarmTimeInMillis, penInt);
}
// Old APIs
else {
if (testMode) Log.d("Ben", "set() - API < 19");
am.set(AlarmManager.RTC_WAKEUP, alarmTimeInMillis, penInt);
}
По сообщениям Log.d я вижу, что на моем устройстве Android 7.1 первый способ setAlarmClock()
выполняется для установки будильника в приемнике.
Я чувствую себя действительно отчаянно после 3 недель неудачных тестов и кодирования - мой будильник сегодня снова сработал на 4 минуты позже - этого никогда не должно происходить, согласно странице обучения режима дремоты:
Сигналы тревоги, установленные с помощью setAlarmClock(), продолжают срабатывать в обычном режиме - система выходит из режима Doze незадолго до срабатывания этих сигналов.
На моем телефоне 7.1 сигнал тревоги будет даже на 20 секунд до 1:40 минут позже, когда я установлю будильник на "сейчас +5 или 6" минут. Может ли кто-нибудь посоветовать мне, как по-настоящему ВСЕГДА выключить будильник вовремя?
1 ответ
Попробуйте использовать:
setExactAndAllowWhileIdle()
Это обеспечит своевременное срабатывание будильника. Я проверил это в моем собственном приложении, и это надежно.
Если вы нацеливаетесь на API менее 23, оставьте это в условии if, которое проверяет текущий API, установленный на устройстве. Используйте это только выше уровня API 23, для отдыха продолжайте использовать setExact
Все права, чтобы ответить на ваш комментарий:
1) Я точно проверил его в режиме ожидания без подключения батареи
2) да, к сожалению, есть один аварийный сигнал на 9-минутный лимит для сигналов тревоги в режиме ожидания. У вас есть две альтернативы здесь:
Сначала используйте setExactAndAllowWhileIdle, чтобы активировать первый сигнал тревоги.
а) Для повторения вам придется использовать метод setAlarmClock
b) для повторения можно запланировать задание JobScheduler с минимальным временем задержки, установленным как время повторения. Это гарантирует, что задание будет по крайней мере запланировано на разрыв интервала повтора. Но только это приведет к тому, что задание будет случайным образом запланировано после интервала, поэтому вам также нужно будет установить крайний срок переопределения, равный 0, чтобы задание планировалось сразу после минимальной задержки. Также сохраняйте требования к сети, поскольку их нет, а режим ожидания необходим по умолчанию или false. Это также так же надежно, как и точные методы сигнализации, согласно моему опыту, и я лично использую этот подход.
В документации указано, что:
Если вам нужно установить будильники, которые срабатывают в режиме Doze, используйте setAndAllowWhileIdle() или setExactAndAllowWhileIdle().
Тревоги, установленные с помощью setAlarmClock(), продолжают срабатывать нормально - система выходит из режима Doze незадолго до того, как сработают эти тревоги.
В разделе "Адаптируйте приложение к Doze" также говорится, что:
Примечание. Ни setAndAllowWhileIdle(), ни setExactAndAllowWhileIdle() не могут активировать сигналы тревоги чаще одного раза в 9 минут для каждого приложения.
В документации для setExactAndAllowWhileIdle говорится, что:
В отличие от других сигналов тревоги, система может перенести этот тип сигнала тревоги, чтобы он не сработал вместе с любыми другими сигналами тревоги, даже с сигналами из того же приложения. Это явно произойдет, когда устройство находится в режиме ожидания (поскольку этот сигнал может срабатывать во время простоя, когда любые другие сигналы от приложения будут удерживаться на более поздний срок), но также может произойти, даже когда оно не находится в режиме ожидания. Обратите внимание, что ОС позволит себе больше гибкости для планирования этих сигналов тревоги, чем обычные точные сигналы тревоги, поскольку приложение выбрало это поведение. Когда устройство находится в режиме ожидания, оно может использовать еще больше возможностей для планирования, чтобы оптимизировать время автономной работы.
Таким образом, setExactAndAllowWhileIdle не гарантирует точное выполнение, а setAlarmClock является более точным (согласно документации).