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, предоставяйки методи за принудително задействане и проверка на броя планирани задачи. За единични тестове на 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 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също