Расписание будильников

Сигналы тревоги (на основе класса AlarmManager ) дают вам возможность выполнять операции, основанные на времени, за пределами срока службы вашего приложения. Например, вы можете использовать сигнал тревоги для запуска длительной операции, например запуска службы один раз в день для загрузки прогноза погоды.

Сигнализация имеет следующие характеристики:

  • Они позволяют запускать намерения в установленное время и/или интервалы.

  • Вы можете использовать их вместе с приемниками широковещательных сообщений для планирования заданий или WorkRequests для выполнения других операций.

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

  • Они помогают вам минимизировать требования к ресурсам вашего приложения. Вы можете планировать операции, не полагаясь на таймеры или постоянно работающие службы.

Установите неточный будильник

Когда приложение устанавливает неточный сигнал тревоги , система подает сигнал тревоги в какой-то момент в будущем. Неточные сигналы тревоги дают некоторые гарантии относительно времени доставки сигналов тревоги при соблюдении ограничений по экономии заряда батареи, таких как Doze .

Разработчики могут использовать следующие гарантии API для настройки времени доставки неточных сигналов тревоги.

Доставка будильника через определенное время

Если ваше приложение вызывает set() , setInexactRepeating() или setAndAllowWhileIdle() , сигнал тревоги никогда не сработает до указанного времени срабатывания.

В Android 12 (уровень API 31) и более поздних версиях система активирует сигнал тревоги в течение одного часа после указанного времени срабатывания, если не действуют какие-либо ограничения по экономии заряда батареи, такие как режим экономии заряда или режим Doze .

Подача сигнала тревоги во временном окне

Если ваше приложение вызывает setWindow() , сигнал тревоги никогда не сработает до истечения указанного времени срабатывания. Если не действуют какие-либо ограничения по экономии заряда батареи, сигнал тревоги доставляется в течение указанного временного окна, начиная с заданного времени срабатывания.

Если ваше приложение предназначено для Android 12 или более поздней версии, система может задержать вызов неточного сигнала тревоги с временным окном как минимум на 10 минут. По этой причине значения параметра windowLengthMillis ниже 600000 обрезаются до 600000 .

Подавайте повторяющийся сигнал тревоги примерно через равные промежутки времени.

Если ваше приложение вызывает setInexactRepeating() , система вызывает несколько сигналов тревоги:

  1. Первый сигнал тревоги сработает в течение указанного временного окна, начиная с заданного времени срабатывания.
  2. Последующие сигналы тревоги обычно срабатывают по истечении указанного временного окна. Время между двумя последовательными вызовами тревоги может различаться.

Установите точный будильник

Система подает точный сигнал тревоги в определенный момент в будущем.

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

Варианты использования, которые могут не требовать точных сигналов тревоги

В следующем списке показаны распространенные рабочие процессы, которые могут не требовать точного сигнала тревоги:

Планирование операций синхронизации на протяжении всего срока службы вашего приложения.
Класс 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

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 . Ваше приложение должно реализовать широковещательный приемник , который выполняет следующие действия:

  1. Подтверждает, что ваше приложение по-прежнему имеет специальный доступ к приложению. Для этого вызовите canScheduleExactAlarms() . Эта проверка защищает ваше приложение от случая, когда пользователь предоставляет вашему приложению разрешение, а затем практически сразу же отменяет его.
  2. Перепланирует любые точные сигналы тревоги, необходимые вашему приложению, в зависимости от его текущего состояния. Эта логика должна быть аналогична тому, что делает ваше приложение, когда оно получает широковещательную рассылку ACTION_BOOT_COMPLETED .

Попросите пользователей предоставить разрешение SCHEDULE_EXACT_ALARM

Опция называется «Разрешить установку будильников и напоминаний».
Рисунок 1. Специальная страница доступа к приложению «Будильники и напоминания» в настройках системы, где пользователи могут разрешить вашему приложению устанавливать точные сигналы тревоги.

При необходимости вы можете отправить пользователей на экран «Будильник и напоминания» в настройках системы, как показано на рисунке 1. Для этого выполните следующие действия:

  1. В пользовательском интерфейсе вашего приложения объясните пользователю, почему вашему приложению необходимо планировать точные сигналы тревоги.
  2. Вызов намерения, которое включает действие намерения 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 продолжит выполнять свою задачу без необходимости вручную перезапускать сигнал тревоги.

Вот шаги:

  1. Установите разрешение RECEIVE_BOOT_COMPLETED в манифесте вашего приложения. Это позволяет вашему приложению получать ACTION_BOOT_COMPLETED , который транслируется после завершения загрузки системы (это работает только в том случае, если приложение уже было запущено пользователем хотя бы один раз):

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  2. Реализуйте 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.
            }
        }
    }
    
  3. Добавьте приемник в файл манифеста вашего приложения с помощью фильтра намерений, который фильтрует действие 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() , система вызывает несколько сигналов тревоги:

  1. Первый сигнал тревоги сработает в течение указанного временного окна, начиная с заданного времени срабатывания.
  2. Последующие сигналы тревоги обычно срабатывают по истечении указанного временного окна. Время между двумя последовательными вызовами тревоги может различаться.

Установите точный будильник

Система подает точный сигнал тревоги в определенный момент в будущем.

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

Варианты использования, которые могут не требовать точных сигналов тревоги

В следующем списке показаны распространенные рабочие процессы, которые могут не требовать точного сигнала тревоги:

Планирование операций синхронизации на протяжении всего срока службы вашего приложения.
Класс 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

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 . Ваше приложение должно реализовать широковещательный приемник , который выполняет следующие действия:

  1. Подтверждает, что ваше приложение по-прежнему имеет специальный доступ к приложению. Для этого вызовите canScheduleExactAlarms() . Эта проверка защищает ваше приложение от случая, когда пользователь предоставляет вашему приложению разрешение, а затем практически сразу же отменяет его.
  2. Перепланирует любые точные сигналы тревоги, необходимые вашему приложению, в зависимости от его текущего состояния. Эта логика должна быть аналогична тому, что делает ваше приложение, когда оно получает широковещательную рассылку ACTION_BOOT_COMPLETED .

Попросите пользователей предоставить разрешение SCHEDULE_EXACT_ALARM

Опция называется «Разрешить установку будильников и напоминаний».
Рисунок 1. Специальная страница доступа к приложению «Будильники и напоминания» в настройках системы, где пользователи могут разрешить вашему приложению устанавливать точные сигналы тревоги.

При необходимости вы можете отправить пользователей на экран «Будильник и напоминания» в настройках системы, как показано на рисунке 1. Для этого выполните следующие действия:

  1. В пользовательском интерфейсе вашего приложения объясните пользователю, почему вашему приложению необходимо планировать точные сигналы тревоги.
  2. Вызов намерения, которое включает действие намерения 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 продолжит выполнять свою задачу без необходимости вручную перезапустить тревогу.

Вот шаги:

  1. Установите разрешение RECEIVE_BOOT_COMPLETED в манифесте вашего приложения. Это позволяет вашему приложению получать ACTION_BOOT_COMPLETED , которое транслируется после того, как система завершает загрузку (это работает только в том случае, если приложение уже было запущено пользователем хотя бы один раз):

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  2. Внедрить 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.
            }
        }
    }
    
  3. Добавьте приемник в файл манифеста вашего приложения с помощью фильтра намерения, который фильтровал на действие 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 если можете. Различные типы сигналов тревоги более подробно описаны в следующем разделе.