AlarmManager
) дают вам возможность выполнять операции, основанные на времени, за пределами срока службы вашего приложения. Например, вы можете использовать сигнал тревоги для запуска длительной операции, например запуска службы один раз в день для загрузки прогноза погоды.Сигнализация имеет следующие характеристики:
Они позволяют запускать намерения в установленное время и/или интервалы.
Вы можете использовать их вместе с приемниками широковещательных сообщений для планирования заданий или WorkRequests для выполнения других операций.
Они работают вне вашего приложения, поэтому вы можете использовать их для запуска событий или действий, даже если ваше приложение не запущено и даже если само устройство находится в спящем режиме.
Они помогают вам минимизировать требования к ресурсам вашего приложения. Вы можете планировать операции, не полагаясь на таймеры или постоянно работающие службы.
Установите неточный будильник
Когда приложение устанавливает неточный сигнал тревоги , система подает сигнал тревоги в какой-то момент в будущем. Неточные сигналы тревоги дают некоторые гарантии относительно времени доставки сигналов тревоги при соблюдении ограничений по экономии заряда батареи, таких как Doze .
Разработчики могут использовать следующие гарантии API для настройки времени доставки неточных сигналов тревоги.
Доставка будильника через определенное время
Если ваше приложение вызывает set()
, setInexactRepeating()
или setAndAllowWhileIdle()
, сигнал тревоги никогда не сработает до указанного времени срабатывания.
В Android 12 (уровень API 31) и более поздних версиях система активирует сигнал тревоги в течение одного часа после указанного времени срабатывания, если не действуют какие-либо ограничения по экономии заряда батареи, такие как режим экономии заряда или режим Doze .
Подача сигнала тревоги во временном окне
Если ваше приложение вызывает setWindow()
, сигнал тревоги никогда не сработает до истечения указанного времени срабатывания. Если не действуют какие-либо ограничения по экономии заряда батареи, сигнал тревоги доставляется в течение указанного временного окна, начиная с заданного времени срабатывания.
Если ваше приложение предназначено для Android 12 или более поздней версии, система может задержать вызов неточного сигнала тревоги с временным окном как минимум на 10 минут. По этой причине значения параметра windowLengthMillis
ниже 600000
обрезаются до 600000
.
Подавайте повторяющийся сигнал тревоги примерно через равные промежутки времени.
Если ваше приложение вызывает setInexactRepeating()
, система вызывает несколько сигналов тревоги:
- Первый сигнал тревоги сработает в течение указанного временного окна, начиная с заданного времени срабатывания.
- Последующие сигналы тревоги обычно срабатывают по истечении указанного временного окна. Время между двумя последовательными вызовами тревоги может различаться.
Установите точный будильник
Система подает точный сигнал тревоги в определенный момент в будущем.
Большинство приложений могут планировать задачи и события с использованием неточных сигналов тревоги для выполнения нескольких распространенных сценариев использования . Если основные функции вашего приложения зависят от точно рассчитанного будильника (например, для приложения-будильника или приложения календаря), то вместо этого можно использовать точный будильник.
Варианты использования, которые могут не требовать точных сигналов тревоги
В следующем списке показаны распространенные рабочие процессы, которые могут не требовать точного сигнала тревоги:
- Планирование операций синхронизации на протяжении всего срока службы вашего приложения.
- Класс
Handler
включает в себя несколько хороших методов для обработки операций синхронизации, например выполнения некоторой работы каждые n секунд, пока ваше приложение активно:postAtTime()
иpostDelayed()
. Обратите внимание, что эти API зависят от времени безотказной работы системы , а не от реального времени . - Запланированная фоновая работа, такая как обновление приложения и загрузка журналов.
-
WorkManager
предоставляет возможность планировать периодическую работу с учетом времени . Вы можете указать интервал повторения иflexInterval
(минимум 15 минут), чтобы точно определить время выполнения работы. - Указанное пользователем действие, которое должно произойти через определенное время (даже если система находится в состоянии ожидания)
- Используйте неточную сигнализацию. В частности, вызовите
setAndAllowWhileIdle()
. - Указанное пользователем действие, которое должно произойти через определенное время
- Используйте неточную сигнализацию. В частности, вызовите
set()
. - Указанное пользователем действие, которое может произойти в течение указанного временного окна.
- Используйте неточную сигнализацию. В частности, вызовите
setWindow()
. Обратите внимание: если ваше приложение предназначено для Android 12 или более поздней версии, наименьшая допустимая длина окна составляет 10 минут.
Способы установки точного будильника
Ваше приложение может устанавливать точные сигналы тревоги, используя один из следующих методов. Эти методы упорядочены таким образом, что те, которые находятся ближе к концу списка, служат более критичным по времени задачам, но требуют больше системных ресурсов.
-
setExact()
Вызовите сигнал тревоги почти в точное время в будущем, пока не будут действовать другие меры по экономии заряда батареи.
Используйте этот метод для установки точных сигналов тревоги, если только работа вашего приложения не критична ко времени для пользователя.
-
setExactAndAllowWhileIdle()
Вызовите сигнал тревоги практически в точное время в будущем, даже если будут действовать меры по экономии заряда батареи.
-
setAlarmClock()
Вызов тревоги в точное время в будущем. Поскольку эти сигналы хорошо видны пользователям, система никогда не корректирует время их доставки. Система определяет эти сигналы тревоги как наиболее критичные и при необходимости оставляет режимы пониженного энергопотребления для доставки сигналов тревоги.
Потребление системных ресурсов
Когда система запускает точные сигналы тревоги, которые устанавливает ваше приложение, устройство потребляет много ресурсов, таких как время автономной работы, особенно если оно находится в режиме энергосбережения. Более того, система не может легко группировать эти запросы для более эффективного использования ресурсов.
Настоятельно рекомендуется по возможности создавать неточный сигнал тревоги . Чтобы выполнить более длительную работу, запланируйте ее с помощью WorkManager
или JobScheduler
из BroadcastReceiver
вашего будильника. Чтобы выполнить работу, пока устройство находится в режиме Doze, создайте неточный сигнал тревоги с помощью setAndAllowWhileIdle()
и запустите задание из сигнала тревоги.
Объявите соответствующее точное разрешение тревоги
Если ваше приложение предназначено для Android 12 или более поздней версии, вам необходимо получить доступ к специальному приложению «Будильники и напоминания». Для этого объявите разрешение SCHEDULE_EXACT_ALARM
в файле манифеста вашего приложения, как показано в следующем фрагменте кода:
<manifest ...> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/> <application ...> ... </application> </manifest>
Если ваше приложение предназначено для Android 13 (уровень API 33) или выше, у вас есть возможность объявить разрешение SCHEDULE_EXACT_ALARM
или USE_EXACT_ALARM
.
<manifest ...> <uses-permission android:name="android.permission.USE_EXACT_ALARM"/> <application ...> ... </application> </manifest>
Хотя разрешения SCHEDULE_EXACT_ALARM
и USE_EXACT_ALARM
сигнализируют об одних и тех же возможностях, они предоставляются по-разному и поддерживают разные варианты использования. Ваше приложение должно использовать точные сигналы тревоги и объявлять разрешение SCHEDULE_EXACT_ALARM
или USE_EXACT_ALARM
, только если функция, ориентированная на пользователя, в вашем приложении требует точно рассчитанных по времени действий.
USE_EXACT_ALARM
- Предоставляется автоматически
- Не может быть отозван пользователем
- В соответствии с новыми правилами Google Play.
- Ограниченные варианты использования
SCHEDULE_EXACT_ALARM
- Предоставлено пользователем
- Более широкий набор вариантов использования
- Приложения должны подтвердить, что разрешение не было отозвано.
Разрешение SCHEDULE_EXACT_ALARM
не предоставляется заранее для новых установок приложений, предназначенных для Android 13 (уровень API 33) и более поздних версий. Если пользователь переносит данные приложения на устройство под управлением Android 14 с помощью операции резервного копирования и восстановления, разрешение SCHEDULE_EXACT_ALARM
будет отклонено на новом устройстве. Однако если существующее приложение уже имеет это разрешение, оно будет предварительно предоставлено при обновлении устройства до Android 14.
Примечание . Если точный сигнал тревоги установлен с использованием объекта OnAlarmListener
, например, с помощью API setExact
, разрешение SCHEDULE_EXACT_ALARM
не требуется.
Использование разрешения SCHEDULE_EXACT_ALARM
В отличие от USE_EXACT_ALARM
, разрешение SCHEDULE_EXACT_ALARM
должно быть предоставлено пользователем. Как пользователь, так и система могут отозвать разрешение SCHEDULE_EXACT_ALARM
.
Чтобы проверить, предоставлено ли разрешение вашему приложению, вызовите canScheduleExactAlarms()
прежде чем пытаться установить точный сигнал тревоги. Когда разрешение SCHEDULE_EXACT_ALARM
для вашего приложения отменяется, ваше приложение останавливается, и все будущие точные сигналы тревоги отменяются. Это также означает, что значение, возвращаемое функцией canScheduleExactAlarms()
остается действительным на протяжении всего жизненного цикла вашего приложения.
Когда вашему приложению предоставлено разрешение SCHEDULE_EXACT_ALARMS
, система отправляет ему широковещательную рассылку ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED
. Ваше приложение должно реализовать широковещательный приемник , который выполняет следующие действия:
- Подтверждает, что ваше приложение по-прежнему имеет специальный доступ к приложению. Для этого вызовите
canScheduleExactAlarms()
. Эта проверка защищает ваше приложение от случая, когда пользователь предоставляет вашему приложению разрешение, а затем практически сразу же отменяет его. - Перепланирует любые точные сигналы тревоги, необходимые вашему приложению, в зависимости от его текущего состояния. Эта логика должна быть аналогична тому, что делает ваше приложение, когда оно получает широковещательную рассылку
ACTION_BOOT_COMPLETED
.
Попросите пользователей предоставить разрешение SCHEDULE_EXACT_ALARM
При необходимости вы можете отправить пользователей на экран «Будильник и напоминания» в настройках системы, как показано на рисунке 1. Для этого выполните следующие действия:
- В пользовательском интерфейсе вашего приложения объясните пользователю, почему вашему приложению необходимо планировать точные сигналы тревоги.
- Вызов намерения, которое включает действие намерения
ACTION_REQUEST_SCHEDULE_EXACT_ALARM
.
Установите повторяющийся будильник
Повторяющиеся сигналы позволяют системе регулярно уведомлять ваше приложение.
Плохо спроектированная сигнализация может привести к разрядке аккумулятора и значительной нагрузке на серверы. По этой причине в Android 4.4 (уровень API 19) и выше все повторяющиеся сигналы тревоги являются неточными .
Повторяющийся сигнал тревоги имеет следующие характеристики:
Тип тревоги. Дополнительную информацию см. в разделе «Выбор типа сигнала тревоги» .
Время триггера. Если указанное вами время срабатывания уже прошло, сигнал тревоги сработает немедленно.
Интервал будильника. Например, один раз в день, каждый час или каждые 5 минут.
Ожидаемое намерение, которое срабатывает при срабатывании сигнализации. Когда вы устанавливаете второй будильник, использующий то же ожидающее намерение, он заменяет исходный будильник.
Чтобы отменить PendingIntent()
, передайте FLAG_NO_CREATE
в PendingIntent.getService()
, чтобы получить экземпляр намерения (если он существует), затем передайте это намерение в AlarmManager.cancel()
Котлин
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as? AlarmManager val pendingIntent = PendingIntent.getService(context, requestId, intent, PendingIntent.FLAG_NO_CREATE) if (pendingIntent != null && alarmManager != null) { alarmManager.cancel(pendingIntent) }
Ява
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); PendingIntent pendingIntent = PendingIntent.getService(context, requestId, intent, PendingIntent.FLAG_NO_CREATE); if (pendingIntent != null && alarmManager != null) { alarmManager.cancel(pendingIntent); }
Выберите тип будильника
Одним из первых соображений при использовании повторяющегося будильника является его тип.
Существует два основных типа часов для сигналов тревоги: «прошедшее реальное время» и «часы реального времени» (RTC). Истекшее реальное время использует «время с момента загрузки системы» в качестве эталона, а часы реального времени используют время UTC (настенные часы). Это означает, что прошедшее реальное время подходит для установки будильника на основе течения времени (например, будильника, который срабатывает каждые 30 секунд), поскольку на него не влияет часовой пояс или региональный стандарт. Тип часов реального времени лучше подходит для сигналов тревоги, которые зависят от текущего языкового стандарта.
Оба типа имеют версию «пробуждения», которая предполагает пробуждение процессора устройства, если экран выключен. Это гарантирует, что сигнализация сработает в запланированное время. Это полезно, если ваше приложение зависит от времени. Например, если у него ограниченное окно для выполнения определенной операции. Если вы не используете версию пробуждения вашего типа будильника, все повторяющиеся будильники сработают, когда ваше устройство в следующий раз проснется.
Если вам просто нужно, чтобы будильник срабатывал через определенный интервал (например, каждые полчаса), используйте один из типов прошедшего реального времени. В целом это лучший выбор.
Если вам нужно, чтобы будильник срабатывал в определенное время суток, выберите один из типов часов реального времени. Однако следует отметить, что этот подход может иметь некоторые недостатки. Приложение может плохо переводиться на другие языки, и если пользователь изменит настройку времени на устройстве, это может привести к неожиданному поведению вашего приложения. Использование типа будильника «часы реального времени» также плохо масштабируется, как обсуждалось выше. Если возможно, мы рекомендуем вам использовать сигнал тревоги «истекло в реальном времени».
Вот список типов:
ELAPSED_REALTIME
: запускает ожидающее намерение в зависимости от времени, прошедшего с момента загрузки устройства, но не пробуждает устройство. Прошедшее время включает в себя любое время, в течение которого устройство находилось в режиме сна.ELAPSED_REALTIME_WAKEUP
: пробуждает устройство и запускает ожидающее намерение по истечении указанного периода времени с момента загрузки устройства.RTC
: запускает ожидающее намерение в указанное время, но не выводит устройство из спящего режима.RTC_WAKEUP
: пробуждает устройство для запуска ожидающего намерения в указанное время.
Примеры истекших сигналов тревоги в реальном времени
Вот несколько примеров использования ELAPSED_REALTIME_WAKEUP
Разбудите устройство, чтобы включить будильник через 30 минут и каждые 30 минут после этого:
Котлин
// Hopefully your alarm will have a lower frequency than this! alarmMgr?.setInexactRepeating( AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR, AlarmManager.INTERVAL_HALF_HOUR, alarmIntent )
Ява
// Hopefully your alarm will have a lower frequency than this! alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR, AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);
Разбудите устройство, чтобы подать одноразовый (неповторяющийся) сигнал тревоги через одну минуту:
Котлин
private var alarmMgr: AlarmManager? = null private lateinit var alarmIntent: PendingIntent ... alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent -> PendingIntent.getBroadcast(context, 0, intent, 0) } alarmMgr?.set( AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 60 * 1000, alarmIntent )
Ява
private AlarmManager alarmMgr; private PendingIntent alarmIntent; ... alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, AlarmReceiver.class); alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0); alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 60 * 1000, alarmIntent);
Примеры будильников реального времени
Вот несколько примеров использования RTC_WAKEUP
.
Разбудите устройство, чтобы включить будильник примерно в 14:00, и повторяйте один раз в день в одно и то же время:
Котлин
// Set the alarm to start at approximately 2:00 p.m. val calendar: Calendar = Calendar.getInstance().apply { timeInMillis = System.currentTimeMillis() set(Calendar.HOUR_OF_DAY, 14) } // With setInexactRepeating(), you have to use one of the AlarmManager interval // constants--in this case, AlarmManager.INTERVAL_DAY. alarmMgr?.setInexactRepeating( AlarmManager.RTC_WAKEUP, calendar.timeInMillis, AlarmManager.INTERVAL_DAY, alarmIntent )
Ява
// Set the alarm to start at approximately 2:00 p.m. Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR_OF_DAY, 14); // With setInexactRepeating(), you have to use one of the AlarmManager interval // constants--in this case, AlarmManager.INTERVAL_DAY. alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, alarmIntent);
Разбудите устройство, чтобы включить будильник ровно в 8:30 утра, а затем каждые 20 минут:
Котлин
private var alarmMgr: AlarmManager? = null private lateinit var alarmIntent: PendingIntent ... alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent -> PendingIntent.getBroadcast(context, 0, intent, 0) } // Set the alarm to start at 8:30 a.m. val calendar: Calendar = Calendar.getInstance().apply { timeInMillis = System.currentTimeMillis() set(Calendar.HOUR_OF_DAY, 8) set(Calendar.MINUTE, 30) } // setRepeating() lets you specify a precise custom interval--in this case, // 20 minutes. alarmMgr?.setRepeating( AlarmManager.RTC_WAKEUP, calendar.timeInMillis, 1000 * 60 * 20, alarmIntent )
Ява
private AlarmManager alarmMgr; private PendingIntent alarmIntent; ... alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, AlarmReceiver.class); alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0); // Set the alarm to start at 8:30 a.m. Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR_OF_DAY, 8); calendar.set(Calendar.MINUTE, 30); // setRepeating() lets you specify a precise custom interval--in this case, // 20 minutes. alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000 * 60 * 20, alarmIntent);
Решите, насколько точным должен быть ваш сигнал тревоги
Как описано ранее, выбор типа сигнала тревоги часто является первым шагом в создании сигнала тревоги. Еще одно различие заключается в том, насколько точным должен быть ваш сигнал тревоги. Для большинства приложений setInexactRepeating()
является правильным выбором. Когда вы используете этот метод, Android синхронизирует несколько неточно повторяющихся сигналов тревоги и запускает их одновременно. Это уменьшает расход заряда аккумулятора.
По возможности избегайте использования точных сигналов тревоги. Однако для редких приложений, у которых есть жесткие требования ко времени, вы можете установить точный сигнал , вызвав setRepeating()
.
С помощью setInexactRepeating()
вы не можете указать собственный интервал, как это можно сделать с помощью setRepeating()
. Вам необходимо использовать одну из констант интервала, например INTERVAL_FIFTEEN_MINUTES
, INTERVAL_DAY
и т. д. Полный список см. в AlarmManager
.
Отменить будильник
В зависимости от вашего приложения вы можете включить возможность отмены будильника. Чтобы отменить сигнал тревоги, вызовите метод cancel()
в диспетчере сигналов тревоги, передав PendingIntent
, который вы больше не хотите активировать. Например:
Котлин
// If the alarm has been set, cancel it. alarmMgr?.cancel(alarmIntent)
Ява
// If the alarm has been set, cancel it. if (alarmMgr!= null) { alarmMgr.cancel(alarmIntent); }
Запустить сигнал тревоги при перезагрузке устройства
По умолчанию все сигналы тревоги отменяются при выключении устройства. Чтобы этого не произошло, вы можете разработать свое приложение для автоматического перезапуска повторяющегося сигнала тревоги, если пользователь перезагружает устройство. Это гарантирует, что AlarmManager
продолжит выполнять свою задачу без необходимости вручную перезапускать сигнал тревоги.
Вот шаги:
Установите разрешение
RECEIVE_BOOT_COMPLETED
в манифесте вашего приложения. Это позволяет вашему приложению получатьACTION_BOOT_COMPLETED
, который транслируется после завершения загрузки системы (это работает только в том случае, если приложение уже было запущено пользователем хотя бы один раз):<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
Реализуйте
BroadcastReceiver
для получения трансляции:Котлин
class SampleBootReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (intent.action == "android.intent.action.BOOT_COMPLETED") { // Set the alarm here. } } }
Ява
public class SampleBootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) { // Set the alarm here. } } }
Добавьте приемник в файл манифеста вашего приложения с помощью фильтра намерений, который фильтрует действие
ACTION_BOOT_COMPLETED
:<receiver android:name=".SampleBootReceiver" android:enabled="false"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"></action> </intent-filter> </receiver>
Обратите внимание, что в манифесте в качестве загрузочного приемника установлено значение
android:enabled="false"
. Это означает, что получатель не будет вызываться, если приложение явно не разрешит это. Это предотвращает ненужный вызов загрузочного приемника. Включить приемник (например, если пользователь устанавливает будильник) можно следующим образом:Котлин
val receiver = ComponentName(context, SampleBootReceiver::class.java) context.packageManager.setComponentEnabledSetting( receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP )
Ява
ComponentName receiver = new ComponentName(context, SampleBootReceiver.class); PackageManager pm = context.getPackageManager(); pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
Если вы включите приемник таким образом, он останется включенным, даже если пользователь перезагрузит устройство. Другими словами, программное включение получателя переопределяет настройку манифеста даже при перезагрузке. Приемник будет оставаться включенным до тех пор, пока ваше приложение не отключит его. Вы можете отключить приемник (например, если пользователь отменяет сигнал тревоги) следующим образом:
Котлин
val receiver = ComponentName(context, SampleBootReceiver::class.java) context.packageManager.setComponentEnabledSetting( receiver, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP )
Ява
ComponentName receiver = new ComponentName(context, SampleBootReceiver.class); PackageManager pm = context.getPackageManager(); pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
Вызов сигналов тревоги, когда устройство находится в режиме ожидания
Устройства под управлением Android 6.0 (уровень API 23) поддерживают режим Doze , который помогает продлить срок службы батареи устройства. Сигналы тревоги не срабатывают, когда устройство находится в режиме ожидания. Любые запланированные сигналы тревоги откладываются до тех пор, пока устройство не выйдет из режима ожидания. Если вам необходимо завершить работу, даже когда устройство находится в режиме ожидания, есть несколько вариантов:
Установите точный будильник .
Используйте API WorkManager, созданный для выполнения фоновой работы. Вы можете указать, что система должна ускорить вашу работу, чтобы работа завершилась как можно скорее. Дополнительную информацию см. в разделе Планирование задач с помощью WorkManager.
Лучшие практики
Каждый выбор, который вы делаете при разработке повторяющегося будильника, может иметь последствия в том, как ваше приложение использует (или злоупотребляет) системные ресурсы. Например, представьте популярное приложение, которое синхронизируется с сервером. Если операция синхронизации основана на времени часов и каждый экземпляр приложения синхронизируется в 23:00, нагрузка на сервер может привести к высокой задержке или даже «отказу в обслуживании». Следуйте этим рекомендациям по использованию сигналов тревоги:
Добавьте случайность (дрожание) к любым сетевым запросам, которые срабатывают в результате повторяющегося сигнала тревоги:
Выполняйте любые локальные работы при срабатывании сигнализации. «Локальная работа» означает все, что не затрагивает сервер и не требует данных с сервера.
В то же время запланируйте срабатывание тревоги, содержащей сетевые запросы, в некоторый случайный период времени.
Сведите частоту сигналов тревоги к минимуму.
Не выводите устройство из спящего режима без необходимости (это поведение определяется типом сигнала тревоги, как описано в разделе «Выбор типа сигнала тревоги »).
Не делайте время срабатывания будильника более точным, чем оно должно быть.
Используйте
setInexactRepeating()
вместоsetRepeating()
. Когда вы используетеsetInexactRepeating()
, Android синхронизирует повторяющиеся сигналы тревоги из нескольких приложений и запускает их одновременно. Это уменьшает общее количество раз, когда система должна вывести устройство из спящего режима, тем самым уменьшая расход заряда аккумулятора. Начиная с Android 4.4 (уровень API 19), все повторяющиеся сигналы тревоги являются неточными . Обратите внимание: хотяsetInexactRepeating()
является улучшением по сравнению сsetRepeating()
, он все равно может перегружать сервер, если каждый экземпляр приложения попадает на сервер примерно в одно и то же время. Поэтому для сетевых запросов добавьте к вашим сигналам тревоги некоторую случайность, как обсуждалось ранее.По возможности не устанавливайте будильник по времени.
Повторяющиеся сигналы тревоги, основанные на точном времени срабатывания, плохо масштабируются. Если можете, используйте
ELAPSED_REALTIME
. Различные типы сигналов тревоги описаны более подробно в следующем разделе.
AlarmManager
) дают вам возможность выполнять операции, основанные на времени, за пределами срока службы вашего приложения. Например, вы можете использовать сигнал тревоги для запуска длительной операции, например запуска службы один раз в день для загрузки прогноза погоды.Сигнализация имеет следующие характеристики:
Они позволяют запускать намерения в установленное время и/или интервалы.
Вы можете использовать их вместе с приемниками широковещательных сообщений для планирования заданий или WorkRequests для выполнения других операций.
Они работают вне вашего приложения, поэтому вы можете использовать их для запуска событий или действий, даже если ваше приложение не запущено и даже если само устройство находится в спящем режиме.
Они помогают вам минимизировать требования к ресурсам вашего приложения. Вы можете планировать операции, не полагаясь на таймеры или постоянно работающие службы.
Установите неточный будильник
Когда приложение устанавливает неточный сигнал тревоги , система подает сигнал тревоги в какой-то момент в будущем. Неточные сигналы тревоги дают некоторые гарантии относительно времени доставки сигналов тревоги при соблюдении ограничений по экономии заряда батареи, таких как Doze .
Разработчики могут использовать следующие гарантии API для настройки времени доставки неточных сигналов тревоги.
Доставка будильника через определенное время
Если ваше приложение вызывает set()
, setInexactRepeating()
или setAndAllowWhileIdle()
, сигнал тревоги никогда не сработает до указанного времени срабатывания.
В Android 12 (уровень API 31) и более поздних версиях система активирует сигнал тревоги в течение одного часа после указанного времени срабатывания, если не действуют какие-либо ограничения по экономии заряда батареи, такие как режим экономии заряда батареи или режим Doze .
Подача сигнала тревоги во временном окне
Если ваше приложение вызывает setWindow()
, сигнал тревоги никогда не сработает до истечения указанного времени срабатывания. Если не действуют какие-либо ограничения по экономии заряда батареи, сигнал тревоги доставляется в течение указанного временного окна, начиная с заданного времени срабатывания.
Если ваше приложение предназначено для Android 12 или более поздней версии, система может задержать вызов неточного сигнала тревоги с временным окном как минимум на 10 минут. По этой причине значения параметра windowLengthMillis
ниже 600000
обрезаются до 600000
.
Подавайте повторяющийся сигнал тревоги примерно через равные промежутки времени.
Если ваше приложение вызывает setInexactRepeating()
, система вызывает несколько сигналов тревоги:
- Первый сигнал тревоги сработает в течение указанного временного окна, начиная с заданного времени срабатывания.
- Последующие сигналы тревоги обычно срабатывают по истечении указанного временного окна. Время между двумя последовательными вызовами тревоги может различаться.
Установите точный будильник
Система подает точный сигнал тревоги в определенный момент в будущем.
Большинство приложений могут планировать задачи и события с использованием неточных сигналов тревоги для выполнения нескольких распространенных сценариев использования . Если основная функциональность вашего приложения зависит от точно рассчитанного будильника (например, для приложения-будильника или приложения календаря), то вместо этого можно использовать точный будильник.
Варианты использования, которые могут не требовать точных сигналов тревоги
В следующем списке показаны распространенные рабочие процессы, которые могут не требовать точного сигнала тревоги:
- Планирование операций синхронизации на протяжении всего срока службы вашего приложения.
- Класс
Handler
включает в себя несколько хороших методов для обработки операций синхронизации, например выполнения некоторой работы каждые n секунд, пока ваше приложение активно:postAtTime()
иpostDelayed()
. Обратите внимание, что эти API зависят от времени безотказной работы системы , а не от реального времени . - Запланированная фоновая работа, такая как обновление приложения и загрузка журналов.
-
WorkManager
предоставляет возможность планировать периодическую работу с учетом времени . Вы можете указать интервал повторения иflexInterval
(минимум 15 минут), чтобы точно определить время выполнения работы. - Указанное пользователем действие, которое должно произойти через определенное время (даже если система находится в состоянии ожидания)
- Используйте неточную сигнализацию. В частности, вызовите
setAndAllowWhileIdle()
. - Указанное пользователем действие, которое должно произойти через определенное время
- Используйте неточную сигнализацию. В частности, вызовите
set()
. - Указанное пользователем действие, которое может произойти в течение указанного временного окна.
- Используйте неточную сигнализацию. В частности, вызовите
setWindow()
. Обратите внимание: если ваше приложение предназначено для Android 12 или более поздней версии, наименьшая допустимая длина окна составляет 10 минут.
Способы установки точного будильника
Ваше приложение может устанавливать точные сигналы тревоги, используя один из следующих методов. Эти методы упорядочены таким образом, что те, которые находятся ближе к концу списка, служат более критичным по времени задачам, но требуют больше системных ресурсов.
-
setExact()
Вызовите сигнал тревоги почти в точное время в будущем, пока не будут действовать другие меры по экономии заряда батареи.
Используйте этот метод для установки точных сигналов тревоги, если только работа вашего приложения не критична ко времени для пользователя.
-
setExactAndAllowWhileIdle()
Вызовите сигнал тревоги практически в точное время в будущем, даже если будут действовать меры по экономии заряда батареи.
-
setAlarmClock()
Вызов тревоги в точное время в будущем. Поскольку эти сигналы хорошо видны пользователям, система никогда не корректирует время их доставки. Система определяет эти сигналы тревоги как наиболее критичные и при необходимости оставляет режимы пониженного энергопотребления для доставки сигналов тревоги.
Потребление системных ресурсов
Когда система запускает точные сигналы тревоги, которые устанавливает ваше приложение, устройство потребляет много ресурсов, таких как время автономной работы, особенно если оно находится в режиме энергосбережения. Более того, система не может легко группировать эти запросы для более эффективного использования ресурсов.
Настоятельно рекомендуется по возможности создавать неточный сигнал тревоги . Чтобы выполнить более длительную работу, запланируйте ее с помощью WorkManager
или JobScheduler
из BroadcastReceiver
вашего будильника. Чтобы выполнить работу, пока устройство находится в режиме Doze, создайте неточный сигнал тревоги с помощью setAndAllowWhileIdle()
и запустите задание из сигнала тревоги.
Объявите соответствующее точное разрешение тревоги
Если ваше приложение предназначено для Android 12 или более поздней версии, вам необходимо получить доступ к специальному приложению «Будильники и напоминания». Для этого объявите разрешение SCHEDULE_EXACT_ALARM
в файле манифеста вашего приложения, как показано в следующем фрагменте кода:
<manifest ...> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/> <application ...> ... </application> </manifest>
Если ваше приложение предназначено для Android 13 (уровень API 33) или выше, у вас есть возможность объявить разрешение SCHEDULE_EXACT_ALARM
или USE_EXACT_ALARM
.
<manifest ...> <uses-permission android:name="android.permission.USE_EXACT_ALARM"/> <application ...> ... </application> </manifest>
Хотя разрешения SCHEDULE_EXACT_ALARM
и USE_EXACT_ALARM
сигнализируют об одних и тех же возможностях, они предоставляются по-разному и поддерживают разные варианты использования. Ваше приложение должно использовать точные сигналы тревоги и объявлять разрешение SCHEDULE_EXACT_ALARM
или USE_EXACT_ALARM
, только если функция, ориентированная на пользователя, в вашем приложении требует точно рассчитанных по времени действий.
USE_EXACT_ALARM
- Предоставляется автоматически
- Не может быть отозван пользователем
- В соответствии с новыми правилами Google Play.
- Ограниченные варианты использования
SCHEDULE_EXACT_ALARM
- Предоставлено пользователем
- Более широкий набор вариантов использования
- Приложения должны подтвердить, что разрешение не было отозвано.
Разрешение SCHEDULE_EXACT_ALARM
не предоставляется заранее для новых установок приложений, предназначенных для Android 13 (уровень API 33) и более поздних версий. Если пользователь переносит данные приложения на устройство под управлением Android 14 с помощью операции резервного копирования и восстановления, на новом устройстве будет отказано в разрешении SCHEDULE_EXACT_ALARM
. Однако если существующее приложение уже имеет это разрешение, оно будет предварительно предоставлено при обновлении устройства до Android 14.
Примечание . Если точный сигнал тревоги установлен с использованием объекта OnAlarmListener
, например, с помощью API setExact
, разрешение SCHEDULE_EXACT_ALARM
не требуется.
Использование разрешения SCHEDULE_EXACT_ALARM
В отличие от USE_EXACT_ALARM
, разрешение SCHEDULE_EXACT_ALARM
должно быть предоставлено пользователем. Как пользователь, так и система могут отозвать разрешение SCHEDULE_EXACT_ALARM
.
Чтобы проверить, предоставлено ли разрешение вашему приложению, вызовите canScheduleExactAlarms()
прежде чем пытаться установить точный сигнал тревоги. Когда разрешение SCHEDULE_EXACT_ALARM
для вашего приложения отменяется, ваше приложение останавливается, и все будущие точные сигналы тревоги отменяются. Это также означает, что значение, возвращаемое функцией canScheduleExactAlarms()
остается действительным на протяжении всего жизненного цикла вашего приложения.
Когда вашему приложению предоставлено разрешение SCHEDULE_EXACT_ALARMS
, система отправляет ему широковещательную рассылку ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED
. Ваше приложение должно реализовать широковещательный приемник , который выполняет следующие действия:
- Подтверждает, что ваше приложение по-прежнему имеет специальный доступ к приложению. Для этого вызовите
canScheduleExactAlarms()
. Эта проверка защищает ваше приложение от случая, когда пользователь предоставляет вашему приложению разрешение, а затем практически сразу же отменяет его. - Перепланирует любые точные сигналы тревоги, необходимые вашему приложению, в зависимости от его текущего состояния. Эта логика должна быть аналогична тому, что делает ваше приложение, когда оно получает широковещательную рассылку
ACTION_BOOT_COMPLETED
.
Попросите пользователей предоставить разрешение SCHEDULE_EXACT_ALARM
При необходимости вы можете отправить пользователей на экран «Будильники и напоминания» в настройках системы, как показано на рисунке 1. Для этого выполните следующие действия:
- В пользовательском интерфейсе вашего приложения объясните пользователю, почему вашему приложению необходимо планировать точные сигналы тревоги.
- Вызов намерения, которое включает действие намерения
ACTION_REQUEST_SCHEDULE_EXACT_ALARM
.
Установите повторяющийся будильник
Повторяющиеся сигналы позволяют системе регулярно уведомлять ваше приложение.
Плохо спроектированная сигнализация может привести к разрядке аккумулятора и значительной нагрузке на серверы. По этой причине в Android 4.4 (уровень API 19) и выше все повторяющиеся сигналы тревоги являются неточными .
Повторяющийся сигнал тревоги имеет следующие характеристики:
Тип тревоги. Дополнительную информацию см. в разделе «Выбор типа сигнала тревоги» .
Время триггера. Если указанное вами время срабатывания уже прошло, сигнал тревоги сработает немедленно.
Интервал будильника. Например, один раз в день, каждый час или каждые 5 минут.
Ожидаемое намерение, которое срабатывает при срабатывании сигнализации. Когда вы устанавливаете второй будильник, использующий то же ожидающее намерение, он заменяет исходный будильник.
Чтобы отменить PendingIntent()
, передайте FLAG_NO_CREATE
в PendingIntent.getService()
, чтобы получить экземпляр намерения (если он существует), затем передайте это намерение в AlarmManager.cancel()
Котлин
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as? AlarmManager val pendingIntent = PendingIntent.getService(context, requestId, intent, PendingIntent.FLAG_NO_CREATE) if (pendingIntent != null && alarmManager != null) { alarmManager.cancel(pendingIntent) }
Ява
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); PendingIntent pendingIntent = PendingIntent.getService(context, requestId, intent, PendingIntent.FLAG_NO_CREATE); if (pendingIntent != null && alarmManager != null) { alarmManager.cancel(pendingIntent); }
Выберите тип будильника
Одним из первых соображений при использовании повторяющегося будильника является его тип.
Существует два основных типа часов для сигналов тревоги: «прошедшее реальное время» и «часы реального времени» (RTC). Истекшее реальное время использует «время с момента загрузки системы» в качестве эталона, а часы реального времени используют время UTC (настенные часы). Это означает, что прошедшее реальное время подходит для установки будильника на основе течения времени (например, будильника, который срабатывает каждые 30 секунд), поскольку на него не влияет часовой пояс или региональный стандарт. Тип часов реального времени лучше подходит для сигналов тревоги, которые зависят от текущего языкового стандарта.
Оба типа имеют версию «пробуждения», которая предполагает пробуждение процессора устройства, если экран выключен. Это гарантирует, что сигнализация сработает в запланированное время. Это полезно, если ваше приложение зависит от времени. Например, если у него ограниченное окно для выполнения определенной операции. Если вы не используете версию пробуждения вашего типа будильника, все повторяющиеся будильники сработают, когда ваше устройство в следующий раз проснется.
Если вам просто нужно, чтобы будильник срабатывал через определенный интервал (например, каждые полчаса), используйте один из типов прошедшего реального времени. В целом это лучший выбор.
Если вам нужно, чтобы будильник срабатывал в определенное время суток, выберите один из типов часов реального времени. Однако следует отметить, что этот подход может иметь некоторые недостатки. Приложение может плохо переводиться на другие языки, и если пользователь изменит настройку времени устройства, это может привести к неожиданному поведению вашего приложения. Использование типа будильника «часы реального времени» также плохо масштабируется, как обсуждалось выше. Если возможно, мы рекомендуем вам использовать сигнал тревоги «истекло в реальном времени».
Вот список типов:
ELAPSED_REALTIME
: запускает ожидающее намерение в зависимости от времени, прошедшего с момента загрузки устройства, но не пробуждает устройство. Прошедшее время включает в себя любое время, в течение которого устройство находилось в режиме сна.ELAPSED_REALTIME_WAKEUP
: разбудит устройство и запускает ожидающие намерения после того, как с момента загрузки устройства истекла указанная продолжительность времени.RTC
: запускает ожидающее намерение в указанное время, но не разбудит устройство.RTC_WAKEUP
: разбудит устройство, чтобы запустить ожидающие намерения в указанное время.
Примеры истекших тревоги в реальном времени
Вот несколько примеров использования ELAPSED_REALTIME_WAKEUP
Разбудите устройство, чтобы запустить тревогу через 30 минут, и каждые 30 минут после этого:
Котлин
// Hopefully your alarm will have a lower frequency than this! alarmMgr?.setInexactRepeating( AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR, AlarmManager.INTERVAL_HALF_HOUR, alarmIntent )
Ява
// Hopefully your alarm will have a lower frequency than this! alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR, AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);
Проснитесь за устройство, чтобы запустить одноразовую (не повторяющуюся) тревогу за одну минуту:
Котлин
private var alarmMgr: AlarmManager? = null private lateinit var alarmIntent: PendingIntent ... alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent -> PendingIntent.getBroadcast(context, 0, intent, 0) } alarmMgr?.set( AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 60 * 1000, alarmIntent )
Ява
private AlarmManager alarmMgr; private PendingIntent alarmIntent; ... alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, AlarmReceiver.class); alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0); alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 60 * 1000, alarmIntent);
Примеры тревоги с часами в реальном времени
Вот несколько примеров использования RTC_WAKEUP
.
Разбудите устройство, чтобы запустить сигнал тревоги примерно в 14:00, и повторяйте один раз в день одновременно:
Котлин
// Set the alarm to start at approximately 2:00 p.m. val calendar: Calendar = Calendar.getInstance().apply { timeInMillis = System.currentTimeMillis() set(Calendar.HOUR_OF_DAY, 14) } // With setInexactRepeating(), you have to use one of the AlarmManager interval // constants--in this case, AlarmManager.INTERVAL_DAY. alarmMgr?.setInexactRepeating( AlarmManager.RTC_WAKEUP, calendar.timeInMillis, AlarmManager.INTERVAL_DAY, alarmIntent )
Ява
// Set the alarm to start at approximately 2:00 p.m. Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR_OF_DAY, 14); // With setInexactRepeating(), you have to use one of the AlarmManager interval // constants--in this case, AlarmManager.INTERVAL_DAY. alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, alarmIntent);
Разбуди устройство, чтобы запустить тревогу в течение 8:30 утра, и каждые 20 минут после этого:
Котлин
private var alarmMgr: AlarmManager? = null private lateinit var alarmIntent: PendingIntent ... alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent -> PendingIntent.getBroadcast(context, 0, intent, 0) } // Set the alarm to start at 8:30 a.m. val calendar: Calendar = Calendar.getInstance().apply { timeInMillis = System.currentTimeMillis() set(Calendar.HOUR_OF_DAY, 8) set(Calendar.MINUTE, 30) } // setRepeating() lets you specify a precise custom interval--in this case, // 20 minutes. alarmMgr?.setRepeating( AlarmManager.RTC_WAKEUP, calendar.timeInMillis, 1000 * 60 * 20, alarmIntent )
Ява
private AlarmManager alarmMgr; private PendingIntent alarmIntent; ... alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, AlarmReceiver.class); alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0); // Set the alarm to start at 8:30 a.m. Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR_OF_DAY, 8); calendar.set(Calendar.MINUTE, 30); // setRepeating() lets you specify a precise custom interval--in this case, // 20 minutes. alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000 * 60 * 20, alarmIntent);
Решите, насколько точностью должна быть ваша тревога
Как описано ранее, выбор типа тревоги часто является первым шагом в создании тревоги. Дальнейшее различие заключается в том, насколько точным вам нужна тревога. Для большинства приложений setInexactRepeating()
является правильным выбором. Когда вы используете этот метод, Android синхронизирует несколько неточных повторяющихся сигналов тревоги и одновременно запускает их. Это уменьшает слив на аккумуляторе.
Избегайте использования точных сигналов тревоги, если это возможно. Тем не менее, для редкого приложения, которое имеет жесткие требования к времени, вы можете установить точную тревогу , вызывая setRepeating()
.
С помощью setInexactRepeating()
вы не можете указать пользовательский интервал, как вы можете с setRepeating()
. Вы должны использовать одну из интервальных констант, такую как INTERVAL_FIFTEEN_MINUTES
, INTERVAL_DAY
и так далее. Смотрите AlarmManager
для полного списка.
Отменить тревогу
В зависимости от вашего приложения вы можете включить возможность отменить сигнализацию. Чтобы отменить сигнал тревоги, вызовите cancel()
на диспетчера тревоги, проходя в PendingIntent
вы больше не хотите стрелять. Например:
Котлин
// If the alarm has been set, cancel it. alarmMgr?.cancel(alarmIntent)
Ява
// If the alarm has been set, cancel it. if (alarmMgr!= null) { alarmMgr.cancel(alarmIntent); }
Запустите тревогу, когда устройство перезагружается
По умолчанию все тревоги отменяются при выключении устройства. Чтобы это не произошло, вы можете разработать свое приложение для автоматического перезагрузки повторяющейся сигнализации, если пользователь перезагрузит устройство. Это гарантирует, что AlarmManager
продолжит выполнять свою задачу без необходимости вручную перезапустить тревогу.
Вот шаги:
Установите разрешение
RECEIVE_BOOT_COMPLETED
в манифесте вашего приложения. Это позволяет вашему приложению получатьACTION_BOOT_COMPLETED
, которое транслируется после того, как система завершает загрузку (это работает только в том случае, если приложение уже было запущено пользователем хотя бы один раз):<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
Внедрить
BroadcastReceiver
для получения трансляции:Котлин
class SampleBootReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (intent.action == "android.intent.action.BOOT_COMPLETED") { // Set the alarm here. } } }
Ява
public class SampleBootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) { // Set the alarm here. } } }
Добавьте приемник в файл манифеста вашего приложения с помощью фильтра намерения, который фильтровал на действие
ACTION_BOOT_COMPLETED
:<receiver android:name=".SampleBootReceiver" android:enabled="false"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"></action> </intent-filter> </receiver>
Обратите внимание, что в манифесте загрузочный приемник установлен на
android:enabled="false"
. Это означает, что приемник не будет вызван, если приложение явно не включает это. Это мешает загрузочному приемнику называться без необходимости. Вы можете включить приемник (например, если пользователь устанавливает тревогу) следующим образом:Котлин
val receiver = ComponentName(context, SampleBootReceiver::class.java) context.packageManager.setComponentEnabledSetting( receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP )
Ява
ComponentName receiver = new ComponentName(context, SampleBootReceiver.class); PackageManager pm = context.getPackageManager(); pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
Как только вы включите приемник таким образом, он останется включенным, даже если пользователь перезагрузит устройство. Другими словами, программно включает в себя приемник переопределяет настройки манифеста даже через перезагрузку. Получатель будет оставаться включенным, пока ваше приложение не отключит его. Вы можете отключить приемник (например, если пользователь отменяет тревогу) следующим образом:
Котлин
val receiver = ComponentName(context, SampleBootReceiver::class.java) context.packageManager.setComponentEnabledSetting( receiver, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP )
Ява
ComponentName receiver = new ComponentName(context, SampleBootReceiver.class); PackageManager pm = context.getPackageManager(); pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
Вызовать сигналы тревоги, пока устройство находится в режиме DOUSE
Устройства, которые запускают Android 6.0 (API Level 23), поддерживают режим Doze , который помогает продлить срок службы батареи устройства. Аварийные сигналы не стреляют, когда устройство находится в режиме Doze. Любые запланированные сигналы тревоги отложены до тех пор, пока устройство не выведет сдачу. Если вам нужно выполнить работу, даже когда устройство простаивает, есть несколько вариантов:
Установите точную тревогу .
Используйте API Workmanager, который построен для выполнения фоновой работы. Вы можете указать, что система должна ускорить вашу работу так, чтобы работа завершилась как можно скорее. Для получения дополнительной информации см. Задачи расписания с Workmanager
Лучшие практики
Каждый выбор, который вы делаете при разработке повторной сигнализации, может иметь последствия в том, как ваше приложение использует (или злоупотребляет) системными ресурсами. Например, представьте себе популярное приложение, которое синхронизирует с сервером. Если операция синхронизации основана на времени часов, а каждый экземпляр приложения синхронизируется в 11:00 вечера, нагрузка на сервер может привести к высокой задержке или даже «отказу в обслуживании». Следуйте этим лучшим практикам в использовании сигналов тревоги:
Добавить случайность (дрожание) в любые сетевые запросы, которые запускают в результате повторяющейся тревоги:
Делайте любую местную работу, когда сигнализирует тревога. «Локальная работа» означает все, что не достигает сервера или требует данных с сервера.
В то же время планируйте тревогу, которая содержит сетевые запросы на стрельбу в течение некоторого случайного периода времени.
Держите свою частоту тревоги к минимуму.
Не разбудите устройство без необходимости (это поведение определяется типом тревоги, как описано в выборе типа тревоги ).
Не делайте время триггера вашего тревоги более точным, чем должно быть.
Используйте
setInexactRepeating()
вместоsetRepeating()
. Когда вы используетеsetInexactRepeating()
, Android синхронизирует повторные сигналы тревоги из нескольких приложений и одновременно запускает их. Это уменьшает общее количество раз, когда система должна разбудить устройство, тем самым уменьшая слив на аккумуляторе. По состоянию на Android 4.4 (уровень API 19), все повторяющиеся сигналы тревоги являются неточной сигнализацией . Обратите внимание, что, хотяsetInexactRepeating()
является улучшением по сравнению сsetRepeating()
, он все еще может сокрушить сервер, если каждый экземпляр приложения попадает на сервер примерно в одно и то же время. Поэтому для сетевых запросов добавьте некоторую случайность к вашим тревогам, как обсуждалось ранее.Старайтесь не основываться на времени на часы, если это возможно.
Повторные сигналы тревоги, основанные на точном времени триггера, плохо масштабируются. Используйте
ELAPSED_REALTIME
если можете. Различные типы сигналов тревоги более подробно описаны в следующем разделе.
AlarmManager
) дают вам возможность выполнить операции на основе времени вне срока службы вашего приложения. Например, вы можете использовать тревогу, чтобы инициировать длительную операцию, например, запустить сервис один раз в день для загрузки прогноза погоды.Аварийные сигналы имеют эти характеристики:
Они позволяют вам стрелять в установленное время и/или интервалы.
Вы можете использовать их в сочетании с вещательными приемниками для планирования рабочих мест или рабочих заводов для выполнения других операций.
Они работают за пределами вашего приложения, поэтому вы можете использовать их для запуска событий или действий, даже если ваше приложение не работает, и даже если само устройство спит.
Они помогают вам минимизировать требования к ресурсам вашего приложения. Вы можете запланировать операции, не полагаясь на таймеры или непрерывный завод услуг.
Установите неточную сигнализацию
Когда приложение устанавливает неточную сигнализацию , система в какой -то момент в будущем обеспечивает сигнал тревоги. Неточные тревоги предоставляют некоторые гарантии относительно сроков доставки тревоги при уважении к ограничению батарей, таких как Dooze .
Разработчики могут использовать следующие гарантии API, чтобы настроить время доставки неточной сигнализации.
Доставить тревогу через определенное время
Если ваше приложение вызывает set()
, setInexactRepeating()
или setAndAllowWhileIdle()
, тревога никогда не уходит до того, как поставляемое время триггера.
На Android 12 (API-уровне 31) и выше, система вызывает тревогу в течение одного часа после поставленного времени триггера, если только какие-либо ограничения на экономию аккумулятора не являются такими, как спасение батареи или доза .
Доставить будильник во время времени
Если ваше приложение вызовет setWindow()
, тревога никогда не уходит до снабженного временем триггера. Если какие-либо ограничения на экономию батареи не вступают в силу, сигнал тревоги доставляется в указанном временном окне, начиная с заданного времени триггера.
Если ваше приложение предназначено для Android 12 или выше, система может задержать вызов неточной сигнализации по времени, по крайней мере, на 10 минут. По этой причине значения параметров windowLengthMillis
под 600000
обрезаны до 600000
.
Доставлять повторяющуюся тревогу с примерно регулярными промежутками
Если ваше приложение вызывает setInexactRepeating()
, система вызывает несколько тревоги:
- Первая тревога уходит в пределах указанного временного окна, начиная с заданного времени триггера.
- Последующие сигналы тревоги обычно уходят после того, как истекло указанное временное окно. Время между двумя последовательными вызовами тревоги может варьироваться.
Установите точную тревогу
Система вызывает точную тревогу в точный момент в будущем.
Большинство приложений могут запланировать задачи и события, используя неточной сигнализации , чтобы завершить несколько общих вариантов использования . Если основная функциональность вашего приложения зависит от точной тревоги-например, для приложения для будильников или приложения календаря-тогда можно вместо этого использовать точную тревогу.
Примеры использования, которые могут не потребовать точных сигналов тревоги
В следующем списке показаны общие рабочие процессы, которые могут не потребовать точной тревоги:
- Планирование операций по срокам на протяжении всей жизни вашего приложения
- Класс
Handler
включает в себя несколько хороших методов для обработки времени времени, таких как выполнение некоторой работы каждые n секунд, в то время как ваше приложение жива:postAtTime()
иpostDelayed()
. Обратите внимание, что эти API основаны на времени безотказной системы , а не в реальном времени . - Запланированная фоновая работа, такая как обновление вашего приложения и загрузка журналов
-
WorkManager
предоставляет способ запланировать чувствительную к сроку периодическую работу . Вы можете предоставить повторный интервал иflexInterval
(минимум 15 минут), чтобы определить гранулированное время выполнения для работы. - Описанное пользователем действие, которое должно произойти через определенное время (даже если система в состоянии холостого хода)
- Используйте неточную сигнализацию. В частности, вызовите
setAndAllowWhileIdle()
. - Описанное пользователем действия, которое должно произойти через определенное время
- Используйте неточную сигнализацию. В частности, вызов
set()
. - Описанное пользователем действие, которое может произойти в течение указанного временного окна
- Используйте неточную сигнализацию. В частности, вызов
setWindow()
. Обратите внимание, что, если ваше приложение нацелено на Android 12 или выше, наименьшая допустимая длина окна составляет 10 минут.
Способы установить точную тревогу
Ваше приложение может установить точные тревоги, используя один из следующих методов. Эти методы упорядочены так, что те, которые ближе к нижней части списка служат больше критических задач, но требуют больше системных ресурсов.
-
setExact()
Вызвать тревогу в почти точное время в будущем, если другие меры по экономии батареи не действуют.
Используйте этот метод, чтобы установить точные сигналы тревоги, если только работа вашего приложения не является критической по времени для пользователя.
-
setExactAndAllowWhileIdle()
Вызовите сигнал тревоги в почти точное время в будущем, даже если действуют меры по экономии батареи.
-
setAlarmClock()
Вызовите тревогу в точное время в будущем. Поскольку эти тревоги очень видны пользователям, система никогда не регулирует свое время доставки. Система идентифицирует эти тревоги как наиболее важные и при необходимости оставляет режимы низкой мощности для доставки сигналов тревоги.
Потребление системных ресурсов
Когда система запускает точные сигналы тревоги, которые устанавливает ваше приложение, устройство потребляет много ресурсов, таких как время автономной работы, особенно если оно находится в режиме экономии энергии. Кроме того, система не может легко отобрать эти запросы, чтобы более эффективно использовать ресурсы.
Настоятельно рекомендуется создать неточную сигнализацию , когда это возможно. Чтобы выполнить более длительную работу, запланируйте ее, используя WorkManager
или JobScheduler
от BroadcastReceiver
вашей тревоги. Чтобы выполнить работу, пока устройство находится в дозе, создайте неточную сигнализацию, используя setAndAllowWhileIdle()
и запустите задание с сигнализации.
Объявить соответствующее точное разрешение на тревогу
Если ваше приложение предназначено для Android 12 или выше, вы должны получить доступ к специальному приложению «тревоги и напоминания». Для этого объявите разрешение SCHEDULE_EXACT_ALARM
в манифестном файле вашего приложения, как показано в следующем фрагменте кода:
<manifest ...> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/> <application ...> ... </application> </manifest>
Если ваше приложение предназначено для Android 13 (API уровня 33) или выше, у вас есть возможность объявить либо SCHEDULE_EXACT_ALARM
, либо разрешение USE_EXACT_ALARM
.
<manifest ...> <uses-permission android:name="android.permission.USE_EXACT_ALARM"/> <application ...> ... </application> </manifest>
В то время как как SCHEDULE_EXACT_ALARM
, так и разрешения USE_EXACT_ALARM
сигнализируют одни и те же возможности, они предоставляются по-разному и поддерживают различные козырьки использования. Ваше приложение должно использовать точные сигналы тревоги и объявлять разрешение SCHEDULE_EXACT_ALARM
или USE_EXACT_ALARM
, только если пользовательская функция в вашем приложении требует точно выполненных действий.
USE_EXACT_ALARM
- Предоставляется автоматически
- Не может быть отозван пользователем
- При условии предстоящей политики Google Play
- Ограниченные варианты использования
SCHEDULE_EXACT_ALARM
- Предоставлен пользователем
- Более широкий набор вариантов использования
- Приложения должны подтвердить, что разрешение не было отменено
Разрешение SCHEDULE_EXACT_ALARM
не предоставляется в свежих установках приложений, нацеленных на Android 13 (уровень API 33) и выше. Если пользователь передает данные приложения на устройство, работающее на Android 14 через операцию резервного копирования и восстановления, в разрешении SCHEDULE_EXACT_ALARM
будет отклонено на новом устройстве. Однако, если существующее приложение уже имеет это разрешение, оно будет предварительно назначено, когда устройство обновится до Android 14.
ПРИМЕЧАНИЕ . Если точная тревога установлена с использованием объекта OnAlarmListener
, например, с API setExact
, разрешение SCHEDULE_EXACT_ALARM
не требуется.
Использование разрешения SCHEDULE_EXACT_ALARM
В отличие от USE_EXACT_ALARM
, пользователь должно предоставить разрешение SCHEDULE_EXACT_ALARM
. Как пользователь, так и система могут отозвать разрешение SCHEDULE_EXACT_ALARM
.
Чтобы проверить, предоставляется ли разрешение вашему приложению, вызовите canScheduleExactAlarms()
прежде чем попытаться установить точную тревогу. Когда для вашего приложения будет отозвано разрешение SCHEDULE_EXACT_ALARM
, останавливается ваше приложение, и все будущие точные тревоги отменены. Это также означает, что значение, возвращаемое canScheduleExactAlarms()
остается действительным на протяжении всего жизненного цикла вашего приложения.
Когда разрешение SCHEDULE_EXACT_ALARMS
предоставляется вашему приложению, система отправляет ему ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED
. Ваше приложение должно реализовать вещательный приемник , который выполняет следующее:
- Подтверждает, что в вашем приложении все еще есть доступ к специальному приложению. Для этого вызовите
canScheduleExactAlarms()
. Эта проверка защищает ваше приложение от случая, когда пользователь предоставляет ваше приложение разрешение, а затем отменяет его почти сразу после этого. - Отправляют любые точные сигналы тревоги, которые нужны вашему приложению, в зависимости от его текущего состояния. Эта логика должна быть похожа на то, что делает ваше приложение, когда оно получает трансляцию
ACTION_BOOT_COMPLETED
.
Попросите пользователей предоставить разрешение SCHEDULE_EXACT_ALARM
При необходимости вы можете отправить пользователей на экран аварийных сигналов и напоминаний в настройках системы, как показано на рисунке 1. Для этого выполните следующие шаги:
- В пользовательском интерфейсе вашего приложения объясните пользователю, почему ваше приложение должно запланировать точные сигналы тревоги.
- Вызвать намерение, которое включает в себя действие
ACTION_REQUEST_SCHEDULE_EXACT_ALARM
.
Установите повторяющуюся тревогу
Повторные сигналы тревоги позволяют системе уведомлять ваше приложение в повторном графике.
Плохо спроектированная тревога может вызвать слив батареи и поставить значительную нагрузку на серверы. По этой причине на Android 4.4 (API -уровне 19) и выше, все повторяющиеся сигналы тревоги являются неточной сигнализацией .
Повторяющая тревога имеет следующие характеристики:
Тип тревоги. Для получения дополнительной информации см. Выберите тип тревоги .
Время триггера. Если время, которое вы указываете, в прошлом, тревога сразу же запускается.
Интервал тревоги. Например, один раз в день, каждый час или каждые 5 минут.
Ожидающее намерение, которое стреляет, когда сигнал тревоги запускается. Когда вы устанавливаете второй сигнал тревоги, который использует то же самое ожидающее намерения, он заменяет исходный сигнал тревоги.
Чтобы отменить PendingIntent()
, пройти FLAG_NO_CREATE
to PendingIntent.getService()
, чтобы получить экземпляр намерения (если оно существует), затем передайте это намерением AlarmManager.cancel()
Котлин
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as? AlarmManager val pendingIntent = PendingIntent.getService(context, requestId, intent, PendingIntent.FLAG_NO_CREATE) if (pendingIntent != null && alarmManager != null) { alarmManager.cancel(pendingIntent) }
Ява
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); PendingIntent pendingIntent = PendingIntent.getService(context, requestId, intent, PendingIntent.FLAG_NO_CREATE); if (pendingIntent != null && alarmManager != null) { alarmManager.cancel(pendingIntent); }
Выберите тип тревоги
Одним из первых соображений при использовании повторяющейся тревоги является его тип.
Существует два общих типа часов для сигналов тревоги: «истекшие в реальном времени» и «часы в реальном времени» (RTC). В качестве справочника в реальном времени используется «время с момента загрузки системы», а часы в реальном времени используют время UTC (настенные часы). Это означает, что истекший в реальном времени подходит для установления тревоги, основанного на течении времени (например, тревоги, которая стреляет каждые 30 секунд), поскольку на него не влияют часовой пояс или локали. Тип часов в реальном времени лучше подходит для сигналов тревоги, которые зависят от текущей локали.
У обоих типов есть версия «пробуждения», которая говорит, что разбудит процессор устройства, если экран выключен. Это гарантирует, что тревога будет стрелять в запланированное время. Это полезно, если в вашем приложении есть зависимость от времени. Например, если он имеет ограниченное окно для выполнения конкретной операции. Если вы не используете версию The Wakeup вашего типа тревоги, то все повторяющиеся сигналы тревоги будут стрелять, когда ваше устройство будет бодрствовать.
Если вам просто нужна тревога для стрельбы с определенным интервалом (например, каждые полчаса), используйте один из прошедших типов реального времени. В общем, это лучший выбор.
Если вам нужна тревога, чтобы стрелять в определенное время суток, выберите один из часов на основе часов в реальном времени. Обратите внимание, однако, что этот подход может иметь некоторые недостатки. Приложение может плохо переводить в другие локалы, и если пользователь изменит настройку времени устройства, оно может вызвать неожиданное поведение в вашем приложении. Использование типа тревоги в реальном времени также не очень хорошо масштабируется, как обсуждалось выше. Мы рекомендуем вам использовать тревогу «истешены в реальном времени», если можете.
Вот список типов:
ELAPSED_REALTIME
: запускает ожидающие намерения в зависимости от количества времени с момента загрузки устройства, но не разбудит устройство. Прошло время включает в себя любое время, когда устройство спало.ELAPSED_REALTIME_WAKEUP
: разбудит устройство и запускает ожидающие намерения после того, как с момента загрузки устройства истекла указанная продолжительность времени.RTC
: запускает ожидающее намерение в указанное время, но не разбудит устройство.RTC_WAKEUP
: разбудит устройство, чтобы запустить ожидающие намерения в указанное время.
Примеры истекших тревоги в реальном времени
Вот несколько примеров использования ELAPSED_REALTIME_WAKEUP
Разбудите устройство, чтобы запустить тревогу через 30 минут, и каждые 30 минут после этого:
Котлин
// Hopefully your alarm will have a lower frequency than this! alarmMgr?.setInexactRepeating( AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR, AlarmManager.INTERVAL_HALF_HOUR, alarmIntent )
Ява
// Hopefully your alarm will have a lower frequency than this! alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR, AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);
Проснитесь за устройство, чтобы запустить одноразовую (не повторяющуюся) тревогу за одну минуту:
Котлин
private var alarmMgr: AlarmManager? = null private lateinit var alarmIntent: PendingIntent ... alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent -> PendingIntent.getBroadcast(context, 0, intent, 0) } alarmMgr?.set( AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 60 * 1000, alarmIntent )
Ява
private AlarmManager alarmMgr; private PendingIntent alarmIntent; ... alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, AlarmReceiver.class); alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0); alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 60 * 1000, alarmIntent);
Примеры тревоги с часами в реальном времени
Вот несколько примеров использования RTC_WAKEUP
.
Разбудите устройство, чтобы запустить сигнал тревоги примерно в 14:00, и повторяйте один раз в день одновременно:
Котлин
// Set the alarm to start at approximately 2:00 p.m. val calendar: Calendar = Calendar.getInstance().apply { timeInMillis = System.currentTimeMillis() set(Calendar.HOUR_OF_DAY, 14) } // With setInexactRepeating(), you have to use one of the AlarmManager interval // constants--in this case, AlarmManager.INTERVAL_DAY. alarmMgr?.setInexactRepeating( AlarmManager.RTC_WAKEUP, calendar.timeInMillis, AlarmManager.INTERVAL_DAY, alarmIntent )
Ява
// Set the alarm to start at approximately 2:00 p.m. Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR_OF_DAY, 14); // With setInexactRepeating(), you have to use one of the AlarmManager interval // constants--in this case, AlarmManager.INTERVAL_DAY. alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, alarmIntent);
Разбуди устройство, чтобы запустить тревогу в течение 8:30 утра, и каждые 20 минут после этого:
Котлин
private var alarmMgr: AlarmManager? = null private lateinit var alarmIntent: PendingIntent ... alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent -> PendingIntent.getBroadcast(context, 0, intent, 0) } // Set the alarm to start at 8:30 a.m. val calendar: Calendar = Calendar.getInstance().apply { timeInMillis = System.currentTimeMillis() set(Calendar.HOUR_OF_DAY, 8) set(Calendar.MINUTE, 30) } // setRepeating() lets you specify a precise custom interval--in this case, // 20 minutes. alarmMgr?.setRepeating( AlarmManager.RTC_WAKEUP, calendar.timeInMillis, 1000 * 60 * 20, alarmIntent )
Ява
private AlarmManager alarmMgr; private PendingIntent alarmIntent; ... alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, AlarmReceiver.class); alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0); // Set the alarm to start at 8:30 a.m. Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR_OF_DAY, 8); calendar.set(Calendar.MINUTE, 30); // setRepeating() lets you specify a precise custom interval--in this case, // 20 minutes. alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000 * 60 * 20, alarmIntent);
Решите, насколько точностью должна быть ваша тревога
Как описано ранее, выбор типа тревоги часто является первым шагом в создании тревоги. Дальнейшее различие заключается в том, насколько точным вам нужна тревога. Для большинства приложений setInexactRepeating()
является правильным выбором. Когда вы используете этот метод, Android синхронизирует несколько неточных повторяющихся сигналов тревоги и одновременно запускает их. Это уменьшает слив на аккумуляторе.
Избегайте использования точных сигналов тревоги, если это возможно. Тем не менее, для редкого приложения, которое имеет жесткие требования к времени, вы можете установить точную тревогу , вызывая setRepeating()
.
С помощью setInexactRepeating()
вы не можете указать пользовательский интервал, как вы можете с setRepeating()
. Вы должны использовать одну из интервальных констант, такую как INTERVAL_FIFTEEN_MINUTES
, INTERVAL_DAY
и так далее. Смотрите AlarmManager
для полного списка.
Отменить тревогу
В зависимости от вашего приложения вы можете включить возможность отменить сигнализацию. Чтобы отменить сигнал тревоги, вызовите cancel()
на диспетчера тревоги, проходя в PendingIntent
вы больше не хотите стрелять. Например:
Котлин
// If the alarm has been set, cancel it. alarmMgr?.cancel(alarmIntent)
Ява
// If the alarm has been set, cancel it. if (alarmMgr!= null) { alarmMgr.cancel(alarmIntent); }
Запустите тревогу, когда устройство перезагружается
По умолчанию все тревоги отменяются при выключении устройства. Чтобы это не произошло, вы можете разработать свое приложение для автоматического перезагрузки повторяющейся сигнализации, если пользователь перезагрузит устройство. Это гарантирует, что AlarmManager
продолжит выполнять свою задачу без необходимости вручную перезапустить тревогу.
Вот шаги:
Установите разрешение
RECEIVE_BOOT_COMPLETED
в манифесте вашего приложения. Это позволяет вашему приложению получатьACTION_BOOT_COMPLETED
, которое транслируется после того, как система завершает загрузку (это работает только в том случае, если приложение уже было запущено пользователем хотя бы один раз):<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
Внедрить
BroadcastReceiver
для получения трансляции:Котлин
class SampleBootReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (intent.action == "android.intent.action.BOOT_COMPLETED") { // Set the alarm here. } } }
Ява
public class SampleBootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) { // Set the alarm here. } } }
Добавьте приемник в файл манифеста вашего приложения с помощью фильтра намерения, который фильтровал на действие
ACTION_BOOT_COMPLETED
:<receiver android:name=".SampleBootReceiver" android:enabled="false"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"></action> </intent-filter> </receiver>
Обратите внимание, что в манифесте загрузочный приемник установлен на
android:enabled="false"
. Это означает, что приемник не будет вызван, если приложение явно не включает это. Это мешает загрузочному приемнику называться без необходимости. Вы можете включить приемник (например, если пользователь устанавливает тревогу) следующим образом:Котлин
val receiver = ComponentName(context, SampleBootReceiver::class.java) context.packageManager.setComponentEnabledSetting( receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP )
Ява
ComponentName receiver = new ComponentName(context, SampleBootReceiver.class); PackageManager pm = context.getPackageManager(); pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
Как только вы включите приемник таким образом, он останется включенным, даже если пользователь перезагрузит устройство. Другими словами, программно включает в себя приемник переопределяет настройки манифеста даже через перезагрузку. Получатель будет оставаться включенным, пока ваше приложение не отключит его. Вы можете отключить приемник (например, если пользователь отменяет тревогу) следующим образом:
Котлин
val receiver = ComponentName(context, SampleBootReceiver::class.java) context.packageManager.setComponentEnabledSetting( receiver, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP )
Ява
ComponentName receiver = new ComponentName(context, SampleBootReceiver.class); PackageManager pm = context.getPackageManager(); pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
Вызовать сигналы тревоги, пока устройство находится в режиме DOUSE
Устройства, которые запускают Android 6.0 (API Level 23), поддерживают режим Doze , который помогает продлить срок службы батареи устройства. Аварийные сигналы не стреляют, когда устройство находится в режиме Doze. Любые запланированные сигналы тревоги отложены до тех пор, пока устройство не выведет сдачу. Если вам нужно выполнить работу, даже когда устройство простаивает, есть несколько вариантов:
Установите точную тревогу .
Используйте API Workmanager, который построен для выполнения фоновой работы. Вы можете указать, что система должна ускорить вашу работу так, чтобы работа завершилась как можно скорее. Для получения дополнительной информации см. Задачи расписания с Workmanager
Лучшие практики
Каждый выбор, который вы делаете при разработке повторной сигнализации, может иметь последствия в том, как ваше приложение использует (или злоупотребляет) системными ресурсами. Например, представьте себе популярное приложение, которое синхронизирует с сервером. Если операция синхронизации основана на времени часов, а каждый экземпляр приложения синхронизируется в 11:00 вечера, нагрузка на сервер может привести к высокой задержке или даже «отказу в обслуживании». Следуйте этим лучшим практикам в использовании сигналов тревоги:
Добавить случайность (дрожание) в любые сетевые запросы, которые запускают в результате повторяющейся тревоги:
Делайте любую местную работу, когда сигнализирует тревога. «Локальная работа» означает все, что не достигает сервера или требует данных с сервера.
В то же время планируйте тревогу, которая содержит сетевые запросы на стрельбу в течение некоторого случайного периода времени.
Держите свою частоту тревоги к минимуму.
Не разбудите устройство без необходимости (это поведение определяется типом тревоги, как описано в выборе типа тревоги ).
Не делайте время триггера вашего тревоги более точным, чем должно быть.
Используйте
setInexactRepeating()
вместоsetRepeating()
. Когда вы используетеsetInexactRepeating()
, Android синхронизирует повторные сигналы тревоги из нескольких приложений и одновременно запускает их. Это уменьшает общее количество раз, когда система должна разбудить устройство, тем самым уменьшая слив на аккумуляторе. По состоянию на Android 4.4 (уровень API 19), все повторяющиеся сигналы тревоги являются неточной сигнализацией . Обратите внимание, что, хотяsetInexactRepeating()
является улучшением по сравнению сsetRepeating()
, он все еще может сокрушить сервер, если каждый экземпляр приложения попадает на сервер примерно в одно и то же время. Поэтому для сетевых запросов добавьте некоторую случайность к вашим тревогам, как обсуждалось ранее.Старайтесь не основываться на времени на часы, если это возможно.
Повторные сигналы тревоги, основанные на точном времени триггера, плохо масштабируются. Используйте
ELAPSED_REALTIME
если можете. Различные типы сигналов тревоги более подробно описаны в следующем разделе.
AlarmManager
) дают вам возможность выполнить операции на основе времени вне срока службы вашего приложения. Например, вы можете использовать тревогу, чтобы инициировать длительную операцию, например, запустить сервис один раз в день для загрузки прогноза погоды.Аварийные сигналы имеют эти характеристики:
Они позволяют вам стрелять в установленное время и/или интервалы.
Вы можете использовать их в сочетании с вещательными приемниками для планирования рабочих мест или рабочих заводов для выполнения других операций.
Они работают за пределами вашего приложения, поэтому вы можете использовать их для запуска событий или действий, даже если ваше приложение не работает, и даже если само устройство спит.
Они помогают вам минимизировать требования к ресурсам вашего приложения. Вы можете запланировать операции, не полагаясь на таймеры или непрерывный завод услуг.
Установите неточную сигнализацию
Когда приложение устанавливает неточную сигнализацию , система в какой -то момент в будущем обеспечивает сигнал тревоги. Неточные тревоги предоставляют некоторые гарантии относительно сроков доставки тревоги при уважении к ограничению батарей, таких как Dooze .
Разработчики могут использовать следующие гарантии API, чтобы настроить время доставки неточной сигнализации.
Доставить тревогу через определенное время
Если ваше приложение вызывает set()
, setInexactRepeating()
или setAndAllowWhileIdle()
, тревога никогда не уходит до того, как поставляемое время триггера.
На Android 12 (API-уровне 31) и выше, система вызывает тревогу в течение одного часа после поставленного времени триггера, если только какие-либо ограничения на экономию аккумулятора не являются такими, как спасение батареи или доза .
Доставить будильник во время времени
Если ваше приложение вызовет setWindow()
, тревога никогда не уходит до снабженного временем триггера. Если какие-либо ограничения на экономию батареи не вступают в силу, сигнал тревоги доставляется в указанном временном окне, начиная с заданного времени триггера.
Если ваше приложение предназначено для Android 12 или выше, система может задержать вызов неточной сигнализации по времени, по крайней мере, на 10 минут. По этой причине значения параметров windowLengthMillis
под 600000
обрезаны до 600000
.
Доставлять повторяющуюся тревогу с примерно регулярными промежутками
Если ваше приложение вызывает setInexactRepeating()
, система вызывает несколько тревоги:
- Первая тревога уходит в пределах указанного временного окна, начиная с заданного времени триггера.
- Последующие сигналы тревоги обычно уходят после того, как истекло указанное временное окно. Время между двумя последовательными вызовами тревоги может варьироваться.
Установите точную тревогу
Система вызывает точную тревогу в точный момент в будущем.
Большинство приложений могут запланировать задачи и события, используя неточной сигнализации , чтобы завершить несколько общих вариантов использования . Если основная функциональность вашего приложения зависит от точной тревоги-например, для приложения для будильников или приложения календаря-тогда можно вместо этого использовать точную тревогу.
Примеры использования, которые могут не потребовать точных сигналов тревоги
В следующем списке показаны общие рабочие процессы, которые могут не потребовать точной тревоги:
- Планирование операций по срокам на протяжении всей жизни вашего приложения
- Класс
Handler
включает в себя несколько хороших методов для обработки времени времени, таких как выполнение некоторой работы каждые n секунд, в то время как ваше приложение жива:postAtTime()
иpostDelayed()
. Обратите внимание, что эти API основаны на времени безотказной системы , а не в реальном времени . - Запланированная фоновая работа, такая как обновление вашего приложения и загрузка журналов
-
WorkManager
предоставляет способ запланировать чувствительную к сроку периодическую работу . Вы можете предоставить повторный интервал иflexInterval
(минимум 15 минут), чтобы определить гранулированное время выполнения для работы. - Описанное пользователем действие, которое должно произойти через определенное время (даже если система в состоянии холостого хода)
- Используйте неточную сигнализацию. В частности, вызовите
setAndAllowWhileIdle()
. - Описанное пользователем действия, которое должно произойти через определенное время
- Используйте неточную сигнализацию. В частности, вызов
set()
. - Описанное пользователем действие, которое может произойти в течение указанного временного окна
- Используйте неточную сигнализацию. В частности, вызов
setWindow()
. Обратите внимание, что, если ваше приложение нацелено на Android 12 или выше, наименьшая допустимая длина окна составляет 10 минут.
Способы установить точную тревогу
Ваше приложение может установить точные тревоги, используя один из следующих методов. Эти методы упорядочены так, что те, которые ближе к нижней части списка служат больше критических задач, но требуют больше системных ресурсов.
-
setExact()
Вызвать тревогу в почти точное время в будущем, если другие меры по экономии батареи не действуют.
Используйте этот метод, чтобы установить точные сигналы тревоги, если только работа вашего приложения не является критической по времени для пользователя.
-
setExactAndAllowWhileIdle()
Вызовите сигнал тревоги в почти точное время в будущем, даже если действуют меры по экономии батареи.
-
setAlarmClock()
Вызовите тревогу в точное время в будущем. Поскольку эти тревоги очень видны пользователям, система никогда не регулирует свое время доставки. Система идентифицирует эти тревоги как наиболее важные и при необходимости оставляет режимы низкой мощности для доставки сигналов тревоги.
Потребление системных ресурсов
Когда система запускает точные сигналы тревоги, которые устанавливает ваше приложение, устройство потребляет много ресурсов, таких как время автономной работы, особенно если оно находится в режиме экономии энергии. Кроме того, система не может легко отобрать эти запросы, чтобы более эффективно использовать ресурсы.
Настоятельно рекомендуется создать неточную сигнализацию , когда это возможно. Чтобы выполнить более длительную работу, запланируйте ее, используя WorkManager
или JobScheduler
от BroadcastReceiver
вашей тревоги. Чтобы выполнить работу, пока устройство находится в дозе, создайте неточную сигнализацию, используя setAndAllowWhileIdle()
и запустите задание с сигнализации.
Объявить соответствующее точное разрешение на тревогу
Если ваше приложение предназначено для Android 12 или выше, вы должны получить доступ к специальному приложению «тревоги и напоминания». Для этого объявите разрешение SCHEDULE_EXACT_ALARM
в манифестном файле вашего приложения, как показано в следующем фрагменте кода:
<manifest ...> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/> <application ...> ... </application> </manifest>
Если ваше приложение предназначено для Android 13 (API уровня 33) или выше, у вас есть возможность объявить либо SCHEDULE_EXACT_ALARM
, либо разрешение USE_EXACT_ALARM
.
<manifest ...> <uses-permission android:name="android.permission.USE_EXACT_ALARM"/> <application ...> ... </application> </manifest>
While both the SCHEDULE_EXACT_ALARM
and the USE_EXACT_ALARM
permissions signal the same capabilities, they are granted differently and support different use-cases. Your app should use exact alarms, and declare either SCHEDULE_EXACT_ALARM
or USE_EXACT_ALARM
permission, only if a user-facing function in your app requires precisely-timed actions.
USE_EXACT_ALARM
- Granted automatically
- Cannot be revoked by the user
- Subject to an upcoming Google Play policy
- Limited use cases
SCHEDULE_EXACT_ALARM
- Granted by the user
- Broader set of use cases
- Apps should confirm that the permission has not been revoked
The SCHEDULE_EXACT_ALARM
permission is not pre-granted to fresh installs of apps targeting Android 13 (API level 33) and higher. If a user transfers app data to a device running Android 14 through a backup-and-restore operation, the SCHEDULE_EXACT_ALARM
permission will be denied on the new device. However, if an existing app already has this permission, it will be pre-granted when the device upgrades to Android 14.
Note : If the exact alarm is set using an OnAlarmListener
object, such as with the setExact
API, the SCHEDULE_EXACT_ALARM
permission isn't required.
Using the SCHEDULE_EXACT_ALARM
permission
Unlike USE_EXACT_ALARM
, the SCHEDULE_EXACT_ALARM
permission must be granted by the user. Both the user and the system can revoke the SCHEDULE_EXACT_ALARM
permission.
To check whether the permission is granted to your app, call canScheduleExactAlarms()
before trying to set an exact alarm. When the SCHEDULE_EXACT_ALARM
permission is revoked for your app, your app stops, and all future exact alarms are canceled. This also means that the value returned by canScheduleExactAlarms()
stays valid for the entire lifecycle of your app.
When the SCHEDULE_EXACT_ALARMS
permission is granted to your app, the system sends it the ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED
broadcast. Your app should implement a broadcast receiver that does the following:
- Confirms that your app still has the special app access. To do so, call
canScheduleExactAlarms()
. This check protects your app from the case where the user grants your app the permission, then revokes it almost immediately afterward. - Reschedules any exact alarms that your app needs, based on its current state. This logic should be similar to what your app does when it receives the
ACTION_BOOT_COMPLETED
broadcast.
Ask users to grant the SCHEDULE_EXACT_ALARM
permission
If necessary, you can send users to the Alarms & reminders screen in system settings, as shown in Figure 1. To do so, complete the following steps:
- In your app's UI, explain to the user why your app needs to schedule exact alarms.
- Invoke an intent that includes the
ACTION_REQUEST_SCHEDULE_EXACT_ALARM
intent action.
Set a repeating alarm
Repeating alarms allow the system to notify your app on a recurring schedule.
A poorly-designed alarm can cause battery drain and put a significant load on servers. For this reason, on Android 4.4 (API level 19) and higher, all repeating alarms are inexact alarms .
A repeating alarm has the following characteristics:
An alarm type. For more discussion, see Choose an alarm type .
A trigger time. If the trigger time you specify is in the past, the alarm triggers immediately.
The alarm's interval. For example, once a day, every hour, or every 5 minutes.
A pending intent that fires when the alarm is triggered. When you set a second alarm that uses the same pending intent, it replaces the original alarm.
To cancel a PendingIntent()
, pass FLAG_NO_CREATE
to PendingIntent.getService()
to get an instance of the intent (if it exists), then pass that intent to AlarmManager.cancel()
Kotlin
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as? AlarmManager val pendingIntent = PendingIntent.getService(context, requestId, intent, PendingIntent.FLAG_NO_CREATE) if (pendingIntent != null && alarmManager != null) { alarmManager.cancel(pendingIntent) }
Ява
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); PendingIntent pendingIntent = PendingIntent.getService(context, requestId, intent, PendingIntent.FLAG_NO_CREATE); if (pendingIntent != null && alarmManager != null) { alarmManager.cancel(pendingIntent); }
Choose an alarm type
One of the first considerations in using a repeating alarm is what its type should be.
There are two general clock types for alarms: "elapsed real time" and "real time clock" (RTC). Elapsed real time uses the "time since system boot" as a reference, and real time clock uses UTC (wall clock) time. This means that elapsed real time is suited to setting an alarm based on the passage of time (for example, an alarm that fires every 30 seconds) since it isn't affected by time zone or locale. The real time clock type is better suited for alarms that are dependent on current locale.
Both types have a "wakeup" version, which says to wake up the device's CPU if the screen is off. This ensures that the alarm will fire at the scheduled time. This is useful if your app has a time dependency. For example, if it has a limited window to perform a particular operation. If you don't use the wakeup version of your alarm type, then all the repeating alarms will fire when your device is next awake.
If you simply need your alarm to fire at a particular interval (for example, every half hour), use one of the elapsed real time types. In general, this is the better choice.
If you need your alarm to fire at a particular time of day, then choose one of the clock-based real time clock types. Note, however, that this approach can have some drawbacks. The app may not translate well to other locales, and if the user changes the device's time setting, it could cause unexpected behavior in your app. Using a real time clock alarm type also does not scale well, as discussed above. We recommend that you use an "elapsed real time" alarm if you can.
Here is the list of types:
ELAPSED_REALTIME
: Fires the pending intent based on the amount of time since the device was booted, but doesn't wake up the device. The elapsed time includes any time during which the device was asleep.ELAPSED_REALTIME_WAKEUP
: Wakes up the device and fires the pending intent after the specified length of time has elapsed since device boot.RTC
: Fires the pending intent at the specified time but does not wake up the device.RTC_WAKEUP
: Wakes up the device to fire the pending intent at the specified time.
Examples of elapsed real time alarms
Here are some examples of using ELAPSED_REALTIME_WAKEUP
Wake up the device to fire the alarm in 30 minutes, and every 30 minutes after that:
Kotlin
// Hopefully your alarm will have a lower frequency than this! alarmMgr?.setInexactRepeating( AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR, AlarmManager.INTERVAL_HALF_HOUR, alarmIntent )
Ява
// Hopefully your alarm will have a lower frequency than this! alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR, AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);
Wake up the device to fire a one-time (non-repeating) alarm in one minute:
Kotlin
private var alarmMgr: AlarmManager? = null private lateinit var alarmIntent: PendingIntent ... alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent -> PendingIntent.getBroadcast(context, 0, intent, 0) } alarmMgr?.set( AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 60 * 1000, alarmIntent )
Ява
private AlarmManager alarmMgr; private PendingIntent alarmIntent; ... alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, AlarmReceiver.class); alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0); alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 60 * 1000, alarmIntent);
Examples of real time clock alarms
Here are some examples of using RTC_WAKEUP
.
Wake up the device to fire the alarm at approximately 2:00 pm, and repeat once a day at the same time:
Kotlin
// Set the alarm to start at approximately 2:00 p.m. val calendar: Calendar = Calendar.getInstance().apply { timeInMillis = System.currentTimeMillis() set(Calendar.HOUR_OF_DAY, 14) } // With setInexactRepeating(), you have to use one of the AlarmManager interval // constants--in this case, AlarmManager.INTERVAL_DAY. alarmMgr?.setInexactRepeating( AlarmManager.RTC_WAKEUP, calendar.timeInMillis, AlarmManager.INTERVAL_DAY, alarmIntent )
Ява
// Set the alarm to start at approximately 2:00 p.m. Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR_OF_DAY, 14); // With setInexactRepeating(), you have to use one of the AlarmManager interval // constants--in this case, AlarmManager.INTERVAL_DAY. alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, alarmIntent);
Wake up the device to fire the alarm at precisely 8:30 am, and every 20 minutes thereafter:
Kotlin
private var alarmMgr: AlarmManager? = null private lateinit var alarmIntent: PendingIntent ... alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent -> PendingIntent.getBroadcast(context, 0, intent, 0) } // Set the alarm to start at 8:30 a.m. val calendar: Calendar = Calendar.getInstance().apply { timeInMillis = System.currentTimeMillis() set(Calendar.HOUR_OF_DAY, 8) set(Calendar.MINUTE, 30) } // setRepeating() lets you specify a precise custom interval--in this case, // 20 minutes. alarmMgr?.setRepeating( AlarmManager.RTC_WAKEUP, calendar.timeInMillis, 1000 * 60 * 20, alarmIntent )
Ява
private AlarmManager alarmMgr; private PendingIntent alarmIntent; ... alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, AlarmReceiver.class); alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0); // Set the alarm to start at 8:30 a.m. Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR_OF_DAY, 8); calendar.set(Calendar.MINUTE, 30); // setRepeating() lets you specify a precise custom interval--in this case, // 20 minutes. alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000 * 60 * 20, alarmIntent);
Decide how precise your alarm needs to be
As previously described, choosing the alarm type is often the first step in creating an alarm. A further distinction is how precise you need your alarm to be. For most apps, setInexactRepeating()
is the right choice. When you use this method, Android synchronizes multiple inexact repeating alarms and fires them at the same time. This reduces the drain on the battery.
Avoid using exact alarms if possible. However, for the rare app that has rigid time requirements, you can set an exact alarm by calling setRepeating()
.
With setInexactRepeating()
, you can't specify a custom interval the way you can with setRepeating()
. You have to use one of the interval constants, such as INTERVAL_FIFTEEN_MINUTES
, INTERVAL_DAY
, and so on. See AlarmManager
for the complete list.
Cancel an alarm
Depending on your app, you may want to include the ability to cancel the alarm. To cancel an alarm, call cancel()
on the Alarm Manager, passing in the PendingIntent
you no longer want to fire. Например:
Kotlin
// If the alarm has been set, cancel it. alarmMgr?.cancel(alarmIntent)
Ява
// If the alarm has been set, cancel it. if (alarmMgr!= null) { alarmMgr.cancel(alarmIntent); }
Start an alarm when the device restarts
By default, all alarms are canceled when a device shuts down. To prevent this from happening, you can design your application to automatically restart a repeating alarm if the user reboots the device. This ensures that the AlarmManager
will continue doing its task without the user needing to manually restart the alarm.
Вот шаги:
Set the
RECEIVE_BOOT_COMPLETED
permission in your application's manifest. This allows your app to receive theACTION_BOOT_COMPLETED
that is broadcast after the system finishes booting (this only works if the app has already been launched by the user at least once):<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
Implement a
BroadcastReceiver
to receive the broadcast:Kotlin
class SampleBootReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (intent.action == "android.intent.action.BOOT_COMPLETED") { // Set the alarm here. } } }
Ява
public class SampleBootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) { // Set the alarm here. } } }
Add the receiver to your app's manifest file with an intent filter that filters on the
ACTION_BOOT_COMPLETED
action:<receiver android:name=".SampleBootReceiver" android:enabled="false"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"></action> </intent-filter> </receiver>
Notice that in the manifest, the boot receiver is set to
android:enabled="false"
. This means that the receiver will not be called unless the application explicitly enables it. This prevents the boot receiver from being called unnecessarily. You can enable a receiver (for example, if the user sets an alarm) as follows:Kotlin
val receiver = ComponentName(context, SampleBootReceiver::class.java) context.packageManager.setComponentEnabledSetting( receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP )
Ява
ComponentName receiver = new ComponentName(context, SampleBootReceiver.class); PackageManager pm = context.getPackageManager(); pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
Once you enable the receiver this way, it will stay enabled, even if the user reboots the device. In other words, programmatically enabling the receiver overrides the manifest setting, even across reboots. The receiver will stay enabled until your app disables it. You can disable a receiver (for example, if the user cancels an alarm) as follows:
Kotlin
val receiver = ComponentName(context, SampleBootReceiver::class.java) context.packageManager.setComponentEnabledSetting( receiver, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP )
Ява
ComponentName receiver = new ComponentName(context, SampleBootReceiver.class); PackageManager pm = context.getPackageManager(); pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
Invoke alarms while the device is in Doze mode
Devices that run Android 6.0 (API level 23) support Doze mode, which helps extend device battery life. Alarms don't fire when the device is in Doze mode Any scheduled alarms are deferred until the device exits Doze. If you need to complete work even when the device is idle, there are several options available:
Set an exact alarm .
Use the WorkManager API, which is built to perform background work. You can indicate that the system should expedite your work so that the work finishes as soon as possible. For more information, see Schedule tasks with WorkManager
Best practices
Every choice you make in designing your repeating alarm can have consequences in how your app uses (or abuses) system resources. For example, imagine a popular app that syncs with a server. If the sync operation is based on clock time and every instance of the app syncs at 11:00 pm, the load on the server could result in high latency or even "denial of service." Follow these best practices in using alarms:
Add randomness (jitter) to any network requests that trigger as a result of a repeating alarm:
Do any local work when the alarm triggers. "Local work" means anything that doesn't hit a server or require the data from the server.
At the same time, schedule the alarm that contains the network requests to fire at some random period of time.
Keep your alarm frequency to a minimum.
Don't wake up the device unnecessarily (this behavior is determined by the alarm type, as described in Choose an alarm type ).
Don't make your alarm's trigger time any more precise than it has to be.
Use
setInexactRepeating()
instead ofsetRepeating()
. When you usesetInexactRepeating()
, Android synchronizes repeating alarms from multiple apps and fires them at the same time. This reduces the total number of times the system must wake the device, thus reducing drain on the battery. As of Android 4.4 (API Level 19), all repeating alarms are inexact alarm . Note that whilesetInexactRepeating()
is an improvement oversetRepeating()
, it can still overwhelm a server if every instance of an app hits the server around the same time. Therefore, for network requests, add some randomness to your alarms, as discussed previously.Avoid basing your alarm on clock time if possible.
Repeating alarms that are based on a precise trigger time don't scale well. Use
ELAPSED_REALTIME
if you can. The different alarm types are described in more detail in the following section.