AlarmManager — это системный сервис Android, который позволяет приложениям выполнять задачи в заданное время, даже если приложение не запущено или устройство находится в режиме сна. В отличие от JobScheduler или WorkManager, AlarmManager гарантирует точность срабатывания, что делает его незаменимым для будильников, календарных напоминаний и задач, критичных ко времени исполнения. По данным Android Developers, 2026, начиная с Android 4.4 setRepeating ведёт себя как неточный повтор, а для точных будильников требуется setExact или setAlarmClock.
Главное
AlarmManager — это системный сервис Android, предоставляющий API для планирования задач с точным или приблизительным временем выполнения. Он существует с первой версии Android и остаётся единственным надёжным способом выполнить код в заданный момент, независимо от состояния приложения и устройства.
Принцип работы прост: приложение отправляет системе PendingIntent с указанием времени срабатывания. Когда наступает нужный момент, система отправляет Intent зарегистрированному BroadcastReceiver или запускает Service. Даже если устройство находилось в спящем режиме, WakeLock позволяет процессору пробудиться и обработать событие.
Основная область применения AlarmManager — задачи, требующие точного времени: будильники, календарные напоминания, запуск длительных операций в определённый час. Для задач, где точность не критична (синхронизация раз в сутки), Google рекомендует WorkManager или JobScheduler, так как они более энергоэффективны.
AlarmManager получает от приложения PendingIntent и время срабатывания. Система сохраняет этот запрос в своём внутреннем планировщике и пробуждает процессор в указанное время для доставки Intent. Разработчик должен заранее зарегистрировать BroadcastReceiver, который обработает этот Intent.
AlarmManager поддерживает 4 типа будильников: ELAPSED_REALTIME (время с момента загрузки, не будит), RTC (реальное время, не будит), ELAPSED_REALTIME_WAKEUP (время с загрузки, будит устройство) и RTC_WAKEUP (реальное время, будит). WAKEUP-версии необходимы, если задача должна выполниться, даже когда устройство спит.
| Тип | Время | Будит | Пример |
|---|---|---|---|
| ELAPSED_REALTIME | с момента загрузки | нет | таймер работы |
| RTC | Unix timestamp | нет | логирование |
| ELAPSED_REALTIME_WAKEUP | с момента загрузки | да | периодическая задача |
| RTC_WAKEUP | Unix timestamp | да | будильник |
Начиная с Android 12 (API 31), для использования точных будильников (setExact) требуется разрешение SCHEDULE_EXACT_ALARM. Пользователь может отозвать его через настройки. Для приложений, которым нужен точный будильник с отображением (например, часы), используется USE_EXACT_ALARM, выдаваемое при установке.
AlarmManager предоставляет три основных метода для планирования задач. Выбор метода определяет точность срабатывания и влияние на энергопотребление устройства.
set — базовый метод для однократного неточного срабатывания. Система может сдвинуть время до нескольких минут для группировки с другими событиями. Подходит для задач, где точность не критична: напоминание о необходимости зайти в приложение.
setRepeating — метод для периодических повторений. Начиная с Android 4.4 (API 19) setRepeating стал неточным — интервалы могут варьироваться. Система больше не гарантирует постоянный период. Вместо setRepeating рекомендуется использовать setExact с повторным планированием или WorkManager с PeriodicWorkRequest.
setExact — метод для точного однократного срабатывания. Система пробуждает устройство в максимально близкое к указанному время. setAlarmClock — особый случай setExact, который также показывает значок будильника в статус-баре и имеет наивысший приоритет среди всех типов будильников.
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
// Точный однократный будильник
val intent = Intent(this, AlarmReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(
this, 0, intent,
PendingIntent.FLAG_IMMUTABLE
)
alarmManager.setAlarmClock(
AlarmManager.AlarmClockInfo(
targetTime, pendingIntent
),
pendingIntent
)
Типичный сценарий — создание ежедневного напоминания в определённое время. Для этого используется RTC_WAKEUP с setExact. При срабатывании BroadcastReceiver запускает уведомление или Service. После обработки необходимо перепланировать задачу на следующий день.
class ReminderReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) {
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE)
as NotificationManager
val notification = NotificationCompat.Builder(
context, "reminder_channel"
)
.setContentTitle("Напоминание")
.setContentText("Пора выполнить задачу")
.setSmallIcon(R.drawable.ic_reminder)
.build()
notificationManager.notify(1001, notification)
}
}
Для повторения на каждый день используется setExact с вычислением следующего срабатывания. В Intent можно передать флаги для идентификации разных типов напоминаний. Убедитесь, что BroadcastReceiver зарегистрирован в AndroidManifest.xml с обработкой действия WAKEUP.
fun scheduleDailyReminder(context: Context, hour: Int, minute: Int) {
val calendar = Calendar.getInstance().apply {
set(Calendar.HOUR_OF_DAY, hour)
set(Calendar.MINUTE, minute)
set(Calendar.SECOND, 0)
if (before(Calendar.getInstance())) {
add(Calendar.DAY_OF_MONTH, 1)
}
}
val alarmManager =
context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
pendingIntent
)
}
AlarmManager — мощный, но энергозатратный инструмент. Каждый WAKEUP-будильник выводит устройство из спящего режима, что расходует заряд батареи. Google рекомендует минимизировать использование точных будильников и предпочитать setExactAndAllowWhileIdle на Android 6+ для снижения влияния на Doze Mode. Для периодических задач без требования к точности используйте WorkManager с PeriodicWorkRequest, который не требует пробуждения устройства и не расходует заряд батареи на каждый запуск.
Для тестирования AlarmManager используйте TestAlarmManager из Android Test Framework. Он позволяет эмулировать срабатывание будильника без ожидания реального времени. В Robolectric доступен ShadowAlarmManager, который перехватывает вызовы set, setExact и setRepeating, предоставляя методы для принудительного срабатывания и проверки количества запланированных задач. Для Unit-тестов BroadcastReceiver используйте Robolectric.getForegroundScheduler(). Также доступен Espresso-тест с IdlingResource, который ожидает срабатывания будильника в интеграционных тестах.
Если приложение использует AlarmManager для периодических задач, не требующих точного времени, рассмотрите миграцию на WorkManager. PeriodicWorkRequest с минимальным интервалом 15 минут заменяет setRepeating, при этом WorkManager гарантирует выполнение после перезагрузки, обрабатывает Doze Mode и не требует разрешения SCHEDULE_EXACT_ALARM. Для задач, критичных ко времени (будильник на 7 утра), AlarmManager остаётся единственным правильным выбором. Оптимальная стратегия — использовать AlarmManager только для будильников с setAlarmClock, а все остальные фоновые задачи перевести на WorkManager.
Для периодических задач без требования к точности используйте WorkManager с PeriodicWorkRequest. Для задач с точным временем, но не критичных к срабатыванию в спящем режиме — setExact без WAKEUP. И только для будильников с обязательным пробуждением — setAlarmClock или RTC_WAKEUP.
Также важно проверять наличие разрешения SCHEDULE_EXACT_ALARM на Android 12+. Если разрешение не выдано, setExact будет работать как обычный set (неточно). Используйте AlarmManager.canScheduleExactAlarms() для проверки. При отсутствии разрешения можно предложить пользователю перейти в настройки через Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM).
Критически важная особенность AlarmManager — все запланированные будильники сбрасываются после перезагрузки устройства. Для их восстановления необходимо объявить BroadcastReceiver, обрабатывающий Intent.ACTION_BOOT_COMPLETED, и перепланировать все активные будильники в методе onReceive. Без этого пользователь потеряет все напоминания после выключения и включения телефона.
class BootReceiver : BroadcastReceiver() {
override fun onReceive(
context: Context,
intent: Intent
) {
if (intent.action ==
Intent.ACTION_BOOT_COMPLETED
) {
val prefs =
context.getSharedPreferences("alarms", 0)
val savedTime =
prefs.getLong("next_alarm", 0L)
if (savedTime > System.currentTimeMillis()) {
scheduleReminder(context, savedTime)
}
}
}
}
На практике AlarmManager остаётся лучшим решением для приложений-будильников, календарей, напоминаний о приёме лекарств и любых задач, где время срабатывания критично для пользователя. Для всех остальных сценариев фоновой работы предпочтительны WorkManager или JobScheduler.
При выборе между AlarmManager и WorkManager руководствуйтесь правилом: если пользователь явно попросил напомнить в 14:30 — используйте AlarmManager с setAlarmClock. Если задача должна выполниться «примерно раз в час» — WorkManager с PeriodicWorkRequest будет энергоэффективнее и надёжнее.
Часто задаваемые вопросы
Оба метода гарантируют точное срабатывание, но setAlarmClock дополнительно показывает значок будильника в статус-баре и информирует систему, что это будильник для пользователя. На Android 6+ setAlarmClock имеет иммунитет от Doze Mode, тогда как setExact может быть отложен.
После перезагрузки все запланированные будильники сбрасываются. Для восстановления необходимо зарегистрировать BroadcastReceiver на действие BOOT_COMPLETED и перепланировать все задачи в onReceive. Без этого ни один будильник не сработает после включения устройства.
Начиная с API 19 setRepeating стал неточным — система может сдвигать интервалы для энергосбережения. Вместо этого используйте setExact с ручным перепланированием или WorkManager с PeriodicWorkRequest, который предоставляет более предсказуемое поведение.
Для setExact требуется разрешение SCHEDULE_EXACT_ALARM, которое пользователь может предоставить или отозвать в настройках. Для setAlarmClock с отображением в интерфейсе часов используется USE_EXACT_ALARM, выдаваемое автоматически при установке из магазина.
Нет, AlarmManager всегда работает через PendingIntent. Это может быть PendingIntent.getBroadcast для BroadcastReceiver, PendingIntent.getService для Service или PendingIntent.getActivity для Activity. Без PendingIntent система не сможет доставить событие приложению.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также