AlarmManager — to systemowa usługa Androida, która pozwala aplikacjom wykonywać zadania o określonej porze, nawet jeśli aplikacja nie jest uruchomiona lub urządzenie znajduje się w trybie uśpienia. W przeciwieństwie do JobScheduler czy WorkManager, AlarmManager gwarantuje precyzyjne wyzwalanie, co czyni go niezastąpionym dla budzików, przypomnień kalendarzowych i zadań krytycznych czasowo. Według Android Developers, 2026, począwszy od Androida 4.4 setRepeating działa jako niedokładne powtórzenie, a do precyzyjnych alarmów wymagany jest setExact lub setAlarmClock.
Najważniejsze
AlarmManager — to systemowa usługa Androida udostępniająca API do planowania zadań z dokładnym lub przybliżonym czasem wykonania. Istnieje od pierwszej wersji Androida i pozostaje jedynym niezawodnym sposobem na wykonanie kodu w określonym momencie, niezależnie od stanu aplikacji i urządzenia.
Zasada działania jest prosta: aplikacja wysyła do systemu PendingIntent z określeniem czasu wyzwolenia. Gdy nadejdzie odpowiedni moment, system wysyła Intent do zarejestrowanego BroadcastReceiver lub uruchamia Service. Nawet jeśli urządzenie było w trybie uśpienia, WakeLock pozwala procesorowi obudzić się i przetworzyć zdarzenie.
Główny obszar zastosowania AlarmManager — zadania wymagające dokładnego czasu: budziki, przypomnienia kalendarzowe, uruchamianie długotrwałych operacji o określonej godzinie. Do zadań, gdzie precyzja nie jest krytyczna (synchronizacja raz dziennie), Google zaleca WorkManager lub JobScheduler, ponieważ są bardziej energooszczędne.
AlarmManager otrzymuje od aplikacji PendingIntent i czas wyzwolenia. System zapisuje to żądanie w swoim wewnętrznym planiście i budzi procesor o określonej porze, aby dostarczyć Intent. Deweloper musi wcześniej zarejestrować BroadcastReceiver, który obsłuży ten Intent.
AlarmManager obsługuje 4 typy alarmów: ELAPSED_REALTIME (czas od uruchomienia, nie budzi), RTC (czas rzeczywisty, nie budzi), ELAPSED_REALTIME_WAKEUP (czas od uruchomienia, budzi urządzenie) i RTC_WAKEUP (czas rzeczywisty, budzi). Wersje WAKEUP są niezbędne, jeśli zadanie ma się wykonać, nawet gdy urządzenie śpi.
| Typ | Czas | Budzi | Przykład |
|---|---|---|---|
| ELAPSED_REALTIME | od uruchomienia | nie | licznik czasu pracy |
| RTC | Unix timestamp | nie | logowanie |
| ELAPSED_REALTIME_WAKEUP | od uruchomienia | tak | zadanie okresowe |
| RTC_WAKEUP | Unix timestamp | tak | budzik |
Począwszy od Androida 12 (API 31), do używania precyzyjnych alarmów (setExact) wymagane jest pozwolenie SCHEDULE_EXACT_ALARM. Użytkownik może je cofnąć w ustawieniach. Dla aplikacji, które potrzebują precyzyjnego alarmu z wyświetlaniem (np. zegar), używane jest USE_EXACT_ALARM, przyznawane podczas instalacji.
AlarmManager udostępnia trzy główne metody planowania zadań. Wybór metody określa precyzję wyzwolenia i wpływ na zużycie energii urządzenia.
set — podstawowa metoda jednorazowego niedokładnego wyzwolenia. System może przesunąć czas o kilka minut w celu grupowania z innymi zdarzeniami. Nadaje się do zadań, gdzie precyzja nie jest krytyczna: przypomnienie o konieczności wejścia do aplikacji.
setRepeating — metoda do okresowych powtórzeń. Począwszy od Androida 4.4 (API 19) setRepeating stał się niedokładny — interwały mogą się zmieniać. System nie gwarantuje już stałego okresu. Zamiast setRepeating zaleca się używanie setExact z ponownym planowaniem lub WorkManager z PeriodicWorkRequest.
setExact — metoda do precyzyjnego jednorazowego wyzwolenia. System budzi urządzenie w czasie jak najbliższym określonemu. setAlarmClock — szczególny przypadek setExact, który dodatkowo pokazuje ikonę budzika na pasku statusu i ma najwyższy priorytet spośród wszystkich typów alarmów.
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
// Precyzyjny pojedynczy alarm
val intent = Intent(this, AlarmReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(
this, 0, intent,
PendingIntent.FLAG_IMMUTABLE
)
alarmManager.setAlarmClock(
AlarmManager.AlarmClockInfo(
targetTime, pendingIntent
),
pendingIntent
)
Typowy scenariusz — tworzenie codziennego przypomnienia o określonej porze. W tym celu używany jest RTC_WAKEUP z setExact. Po wyzwoleniu BroadcastReceiver uruchamia powiadomienie lub Service. Po przetworzeniu należy zaplanować zadanie ponownie na następny dzień.
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("Przypomnienie")
.setContentText("Czas wykonać zadanie")
.setSmallIcon(R.drawable.ic_reminder)
.build()
notificationManager.notify(1001, notification)
}
}
Do codziennego powtarzania używany jest setExact z obliczeniem następnego wyzwolenia. W Intent można przekazać flagi do identyfikacji różnych typów przypomnień. Upewnij się, że BroadcastReceiver jest zarejestrowany w AndroidManifest.xml z obsługą akcji 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 — potężne, ale energochłonne narzędzie. Każdy alarm WAKEUP wybudza urządzenie z trybu uśpienia, co zużywa baterię. Google zaleca minimalizowanie użycia precyzyjnych alarmów i preferowanie setExactAndAllowWhileIdle na Androidzie 6+ w celu zmniejszenia wpływu na Doze Mode. Do zadań okresowych bez wymogu precyzji używaj WorkManager z PeriodicWorkRequest, który nie wymaga budzenia urządzenia i nie zużywa baterii przy każdym uruchomieniu.
Do testowania AlarmManager używaj TestAlarmManager z Android Test Framework. Pozwala on emulować wyzwolenie alarmu bez oczekiwania na rzeczywisty czas. W Robolectric dostępny jest ShadowAlarmManager, który przechwytuje wywołania set, setExact i setRepeating, udostępniając metody do wymuszonego wyzwolenia i sprawdzania liczby zaplanowanych zadań. Do testów jednostkowych BroadcastReceiver używaj Robolectric.getForegroundScheduler(). Dostępny jest również test Espresso z IdlingResource, który oczekuje na wyzwolenie alarmu w testach integracyjnych.
Jeśli aplikacja używa AlarmManager do zadań okresowych niewymagających dokładnego czasu, rozważ migrację na WorkManager. PeriodicWorkRequest z minimalnym interwałem 15 minut zastępuje setRepeating, przy czym WorkManager gwarantuje wykonanie po ponownym uruchomieniu, obsługuje Doze Mode i nie wymaga pozwolenia SCHEDULE_EXACT_ALARM. Do zadań krytycznych czasowo (budzik na 7 rano) AlarmManager pozostaje jedynym właściwym wyborem. Optymalna strategia — używać AlarmManager tylko do budzików z setAlarmClock, a wszystkie inne zadania w tle przenieść na WorkManager.
Do zadań okresowych bez wymogu precyzji używaj WorkManager z PeriodicWorkRequest. Do zadań z dokładnym czasem, ale niekrytycznych do wyzwolenia w trybie uśpienia — setExact bez WAKEUP. I tylko do budzików z obowiązkowym budzeniem — setAlarmClock lub RTC_WAKEUP.
Ważne jest również sprawdzanie obecności pozwolenia SCHEDULE_EXACT_ALARM na Androidzie 12+. Jeśli pozwolenie nie zostało przyznane, setExact będzie działać jak zwykły set (niedokładnie). Używaj AlarmManager.canScheduleExactAlarms() do sprawdzenia. W przypadku braku pozwolenia można zaproponować użytkownikowi przejście do ustawień przez Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM).
Krytycznie ważna cecha AlarmManager — wszystkie zaplanowane alarmy są resetowane po ponownym uruchomieniu urządzenia. Do ich przywrócenia należy zadeklarować BroadcastReceiver obsługujący Intent.ACTION_BOOT_COMPLETED i zaplanować ponownie wszystkie aktywne alarmy w metodzie onReceive. Bez tego użytkownik straci wszystkie przypomnienia po wyłączeniu i włączeniu telefonu.
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)
}
}
}
}
W praktyce AlarmManager pozostaje najlepszym rozwiązaniem dla aplikacji budzików, kalendarzy, przypomnień o przyjmowaniu leków i wszelkich zadań, gdzie czas wyzwolenia jest krytyczny dla użytkownika. Dla wszystkich innych scenariuszy pracy w tle preferowane są WorkManager lub JobScheduler.
Przy wyborze między AlarmManager a WorkManager kieruj się zasadą: jeśli użytkownik wyraźnie poprosił o przypomnienie o 14:30 — użyj AlarmManager z setAlarmClock. Jeśli zadanie ma się wykonać „mniej więcej raz na godzinę" — WorkManager z PeriodicWorkRequest będzie bardziej energooszczędny i niezawodny.
Często zadawane pytania
Obie metody gwarantują precyzyjne wyzwolenie, ale setAlarmClock dodatkowo pokazuje ikonę budzika na pasku statusu i informuje system, że to alarm dla użytkownika. Na Androidzie 6+ setAlarmClock ma odporność na Doze Mode, podczas gdy setExact może być opóźniony.
Po ponownym uruchomieniu wszystkie zaplanowane alarmy są resetowane. Do przywrócenia należy zarejestrować BroadcastReceiver dla akcji BOOT_COMPLETED i zaplanować ponownie wszystkie zadania w onReceive. Bez tego żaden alarm nie zadziała po włączeniu urządzenia.
Począwszy od API 19 setRepeating stał się niedokładny — system może przesuwać interwały w celu oszczędzania energii. Zamiast tego używaj setExact z ręcznym ponownym planowaniem lub WorkManager z PeriodicWorkRequest, który zapewnia bardziej przewidywalne zachowanie.
Dla setExact wymagane jest pozwolenie SCHEDULE_EXACT_ALARM, które użytkownik może przyznać lub cofnąć w ustawieniach. Dla setAlarmClock z wyświetlaniem w interfejsie zegara używane jest USE_EXACT_ALARM, przyznawane automatycznie podczas instalacji ze sklepu.
Nie, AlarmManager zawsze działa przez PendingIntent. Może to być PendingIntent.getBroadcast dla BroadcastReceiver, PendingIntent.getService dla Service lub PendingIntent.getActivity dla Activity. Bez PendingIntent system nie będzie w stanie dostarczyć zdarzenia do aplikacji.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również