Примітка. Я спробував різні рішення, про які написано тут у StackOverflow (приклад тут ). Будь ласка, не закривайте це, не перевіряючи, чи працює ваше рішення з того, що ви знайшли, використовуючи тест, про який я писав нижче.
Фон
У програмі є вимога: користувач встановлює нагадування, яке має бути заплановано на певний час, тому коли програма запускається в цей час, вона робить щось крихітне у фоновому режимі (лише деяка операція запиту БД) і показує просте повідомлення, щоб розповісти про нагадування.
Раніше я використовував простий код, щоб встановити щось, що планується запланувати на відносно певний час:
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 (на складі).
Я читав у документах про налаштування тривоги, про те, що вона обмежена для додатків, щоб вона не виникала надто часто, але це не пояснює, як встановити будильник на певний час, і це не пояснює як це додаток Google Clock вдається це зробити.
Мало того, але, як я розумію, він говорить, що обмеження слід застосовувати особливо для стану малої потужності пристрою, але в моєму випадку я не мав цього стану і на пристрої, і на емуляторах. Я встановив, що тривоги будуть спрацьовувати приблизно через хвилину.
Бачачи, що багато додатків будильника вже не працюють, як раніше, я думаю, що в документах чогось не вистачає. Прикладом таких додатків є популярний додаток Timely , який купував Google, але ніколи не отримував нових оновлень, щоб обробляти нові обмеження, і тепер користувачі хочуть його повернути. . Однак деякі популярні додатки справно працюють, наприклад, цей .
Що я спробував
Щоб перевірити, чи справді спрацьовує тривога, я виконую ці тести, коли намагаюся спрацювати тривогу через хвилину, після того, як вперше встановив додаток, все під час підключення пристрою до ПК (щоб побачити журнали):
- Перевірте, коли програма стоїть на передньому плані, видно користувачеві. - зайняли 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 , щоб перепланувати будильник там, але це теж не допомогло (сервіс працював нормально).
Що стосується програми Clock від Google, я не бачив нічого особливого в цьому, окрім того, що воно показує сповіщення перед запуском, і я також не бачу його в розділі "не оптимізовано" на екрані налаштувань оптимізації акумулятора.
Побачивши, що це здається помилкою, я повідомив про це тут , включаючи зразок проекту та відео, щоб показати проблему.
Я перевірив кілька версій емулятора, і схоже, що така поведінка почалася з API 27 (Android 8.1 - Oreo). Дивлячись на документи , я не бачу згадування AlarmManager, але натомість було написано про різні фонові роботи.
Питання
Як ми встановимо щось, що може спрацювати у відносно точний час у наш час?
Чому вищезазначені рішення більше не працюють? Я щось пропускаю? Дозвіл? Можливо, замість цього я повинен використовувати Worker? Але чи не означало б це, що воно може не спрацьовувати вчасно?
Як додаток Google "Годинник" долає все це і все-таки спрацьовує в точний час завжди, навіть якщо це було запущено лише хвилину тому? Це лише тому, що це системний додаток? Що робити, якщо він встановлюється як користувальницький додаток на пристрої, в якому його немає?
Якщо ви говорите , що це тому , що це системне додаток, я знайшов інший додаток , яке може викликати тривогу в два рази в протягом 2 хвилин, тут , хоча я думаю , що він може використовувати службу переднього плану іноді.
EDIT: створив крихітний сховище Github, щоб спробувати ідеї тут .
EDIT: нарешті знайдено зразок, який є і з відкритими джерелами, і не має цієї проблеми. На жаль, це дуже складно, і я все ще намагаюся розібратися, що робить його таким різним (і який мінімальний код, який я повинен додати до своєї POC), що дозволяє його тривоги залишатись запланованими після видалення програми з останніх завдань