Примечание: я пробовал различные решения, о которых написано здесь, в StackOverflow (пример здесь ). Пожалуйста, не закрывайте это, не проверяя, работает ли ваше решение из того, что вы нашли, используя тест, который я написал ниже.
Фон
В приложении есть требование, чтобы пользователь устанавливает напоминание, которое должно быть запланировано на определенное время c, поэтому, когда приложение запускается в это время, оно делает что-то крошечное в фоновом режиме (просто некоторая операция запроса к БД) и показывает простое уведомление, чтобы сообщить о напоминании .
Раньше я использовал простой код, чтобы установить что-то для планирования на относительно конкретное c время:
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val pendingIntent = PendingIntent.getBroadcast(context, requestId, Intent(context, AlarmReceiver::class.java), PendingIntent.FLAG_UPDATE_CURRENT)
when {
VERSION.SDK_INT >= VERSION_CODES.KITKAT -> alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
else -> alarmManager.set(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
}
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d("AppLog", "AlarmReceiver onReceive")
//do something in the real app
}
}
Использование:
val timeToTrigger = System.currentTimeMillis() + java.util.concurrent.TimeUnit.MINUTES.toMillis(1)
setAlarm(this, timeToTrigger, 1)
Проблема
Я сейчас тестировал этот код на эмуляторах на новых Android версиях и на Pixel 4 с Android 10, и он, похоже, не срабатывает, а может и не срабатывает после очень долгого времени, с тех пор как я это предоставляю. Мне хорошо известно о ужасном поведении , которое некоторых OEM * добавлено для удаления приложений из недавних задач, но этот включен и эмуляторы, и устройство Pixel 4. (в наличии).
Я прочитал на документах о настройке будильника, что он ограничен для приложений, так что это не будет происходить слишком часто, но это не объясняет, как установить будильник в определенное время c, и не объясняет, почему приложению Google Clock это удается.
Не только это, но в соответствии с тем, что я понимаю, в нем говорится, что ограничения должны применяться, особенно в отношении состояния устройства с низким энергопотреблением, но в моем случае у меня не было этого состояния, как на устройстве, так и на эмуляторах. Я установил, что аварийные сигналы должны срабатывать примерно через минуту.
Видя, что многие приложения с будильником больше не работают, как раньше, я думаю, что в документах чего-то не хватает. Примером таких приложений является популярное приложение Timely , которое было куплено Google , но никогда не получало новых обновлений для обработки новых ограничений, и теперь пользователи хотят его вернуть., Однако некоторые популярные приложения работают нормально, например , это .
Что я пробовал
Чтобы проверить, действительно ли работает будильник, я выполняю эти тесты, когда Попытка включить будильник через минуту, после первой установки приложения, все время, пока устройство подключено к P C (для просмотра журналов):
- Проверка, когда приложение находится на переднем плане, видимое для пользователя. - заняло 1-2 минуты.
- Проверка, когда приложение было отправлено в фоновый режим (например, с помощью кнопки «Домой»), - прошло около 1 минуты
- Проверка, когда задача приложения была удалена из недавние задачи. - Я ждал более 20 минут и не видел срабатывания будильника, записи в журналы.
- Как # 3, но и выключил экран. Наверное, было бы хуже ...
Я пытался использовать следующие вещи, все не работают:
alarmManager.setAlarmClock(AlarmManager.AlarmClockInfo(timeToTrigger, pendingIntent), pendingIntent)
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
комбинация любого из вышеперечисленных, с:
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT)
alarmManager.setWindow(AlarmManager.RTC_WAKEUP, 0, 60 * 1000L, pendingIntent)
Попытка использовать службу вместо BroadcastReceiver. Также попробовал другой процесс.
Попытка заставить приложение игнорироваться из-за оптимизации батареи (не помогло), но так как другие приложения не нуждаются в этом, я не должен используйте его либо.
Попробовал с помощью этого:
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP)
alarmManager.setAlarmClock(AlarmManager.AlarmClockInfo(timeToTrigger, pendingIntent), pendingIntent)
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
Попытка иметь службу, которая будет иметь триггер
onTaskRemoved , чтобы перепланировать тревогу там, но это также не помогло (хотя служба работала нормально).
Что касается приложения Google Clock, я не увидел в нем ничего особенного, за исключением того, что оно отображает уведомление до его запуска, а также я не вижу его в разделе «неоптимизировано» экрана настроек оптимизации батареи. .
Видя, что это похоже на ошибку, я сообщил об этом здесь , включая пример проекта и видео, чтобы показать проблему.
Я проверил на нескольких версиях эмулятора, и кажется, что это поведение началось с API 27 (Android 8.1 - Oreo). Смотря на документы , я не вижу упоминания AlarmManager, но вместо этого было написано о различных фоновых работах.
Вопросы
Как мы устанавливаем что-то для запуска в относительно точное время в наше время?
Почему вышеперечисленные решения больше не работают? Я что-то упустил? Разрешение? Может быть, я должен использовать вместо Worker? Но не значит ли это, что он вообще может не сработать вовремя?
Как приложение Google "Часы" преодолевает все это и в любом случае срабатывает в точное время, всегда , даже если это сработало всего минуту go? Только потому, что это системное приложение? Что, если оно будет установлено как пользовательское приложение на устройстве, которое не имеет встроенного?
Если вы скажете, что это потому, что это системное приложение, я обнаружил, что другое приложение, которое может вызвать тревогу дважды за 2 минуты, здесь , хотя я думаю, что иногда оно может использовать службу переднего плана.
РЕДАКТИРОВАТЬ: сделал крошечный репозиторий Github, чтобы примерить идеи, здесь .
РЕДАКТИРОВАТЬ: наконец нашел образец , который является как открытым исходным кодом, так и не есть эта проблема. К сожалению, это очень сложно, и я все еще пытаюсь выяснить, что делает его настолько отличным (и какой минимальный код я должен добавить к своему PO C), что позволяет планировать его сигналы тревоги после удаления приложения из недавних задач