Planowanie alarmów

Alarmy (oparte na klasie AlarmManager) umożliwiają wykonywanie operacji opartych na czasie poza okresem istnienia aplikacji. Możesz na przykład użyć alarmu, aby zainicjować długotrwałą operację, np. uruchamiać usługę raz dziennie w celu pobrania prognozy pogody.

Alarmy mają te cechy:

  • Umożliwiają one wywoływanie intencji o ustalonych porach lub w określonych odstępach czasu.

  • Możesz ich używać w połączeniu z odbiornikami transmisji, aby planować zadania lub WorkRequest do wykonywania innych operacji.

  • Działają one poza aplikacją, więc możesz ich używać do wywoływania zdarzeń lub działań nawet wtedy, gdy aplikacja nie jest uruchomiona, a nawet gdy urządzenie jest uśpione.

  • Pomagają one zminimalizować wymagania aplikacji dotyczące zasobów. Możesz planować operacje bez polegania na timerach lub ciągłym działaniu usług.

Ustawianie niedokładnego alarmu

Gdy aplikacja ustawi niedokładny alarm, system włączy go w przyszłości. Niedokładne alarmy zapewniają pewne gwarancje dotyczące czasu dostarczenia alarmu, a jednocześnie uwzględniają ograniczenia związane z oszczędzaniem baterii, takie jak tryb uśpienia.

Deweloperzy mogą korzystać z tych gwarancji interfejsu API, aby dostosowywać czas dostarczania niedokładnych alarmów.

Włączenie alarmu po określonym czasie

Jeśli Twoja aplikacja wywołuje funkcje set(), setInexactRepeating() lub setAndAllowWhileIdle(), alarm nigdy nie włączy się przed podanym czasem wyzwalania.

W Androidzie 12 (poziom API 31) i nowszych system wywołuje alarm w ciągu godziny od podanego czasu wywołania, chyba że obowiązują ograniczenia związane z oszczędzaniem baterii, takie jak oszczędzanie baterii lub tryb uśpienia.

Włączenie alarmu w określonym przedziale czasu

Jeśli aplikacja wywoła setWindow(), alarm nigdy nie włączy się przed podanym czasem wywołania. O ile nie obowiązują żadne ograniczenia dotyczące oszczędzania baterii, alarm jest dostarczany w określonym przedziale czasu, począwszy od podanego czasu wywołania.

Jeśli aplikacja jest przeznaczona na Androida 12 lub nowszego, system może opóźnić wywołanie nieprecyzyjnego alarmu w oknie czasowym o co najmniej 10 minut. Z tego powodu wartości parametru windowLengthMillis w sekcji 600000 są przycinane do 600000.

Włączanie powtarzającego się alarmu w mniej więcej regularnych odstępach czasu

Jeśli aplikacja wywołuje setInexactRepeating(), system wywołuje kilka alarmów:

  1. Pierwszy alarm włączy się w określonym przedziale czasu, począwszy od podanego czasu wyzwalania.
  2. Kolejne alarmy zwykle włączają się po upływie określonego przedziału czasu. Czas między kolejnymi wywołaniami alarmu może się różnić.

Ustawianie precyzyjnego alarmu

System wywołuje dokładny alarm w określonym momencie w przyszłości.

Większość aplikacji może planować zadania i wydarzenia za pomocą nieprecyzyjnych alarmów, aby realizować różne typowych przypadków użycia. Jeśli główna funkcja aplikacji zależy od precyzyjnego alarmu, np. w przypadku aplikacji budzika lub kalendarza, możesz użyć alarmu precyzyjnego.

Zastosowania, które mogą nie wymagać alarmów precyzyjnych

Poniżej znajdziesz listę typowych przepływów pracy, które nie wymagają dokładnego alarmu:

Planowanie operacji związanych z czasem w okresie istnienia aplikacji
Klasa Handler zawiera kilka dobrych metod obsługi operacji związanych z czasem, np. wykonywania pewnych działań co n sekund, gdy aplikacja jest aktywna:postAtTime()postDelayed(). Pamiętaj, że te interfejsy API zależą od czasu działania systemu, a nie od czasu rzeczywistego.
zaplanowane działania w tle, takie jak aktualizowanie aplikacji i przesyłanie logów;
WorkManager umożliwia planowanie okresowych zadań, w przypadku których istotny jest czas. Możesz podać interwał powtarzania i flexInterval (minimum 15 minut), aby określić szczegółowy czas działania zadania.
Działanie określone przez użytkownika, które powinno nastąpić po upływie określonego czasu (nawet jeśli system jest w stanie bezczynności).
Użyj alarmu nieprecyzyjnego. Zadzwoń pod numer setAndAllowWhileIdle().
Działanie określone przez użytkownika, które powinno nastąpić po upływie określonego czasu
Użyj alarmu nieprecyzyjnego. Zadzwoń pod numer set().
Działanie określone przez użytkownika, które może wystąpić w określonym przedziale czasu.
Użyj alarmu nieprecyzyjnego. Zadzwoń pod numer setWindow(). Pamiętaj, że jeśli Twoja aplikacja jest kierowana na Androida 12 lub nowszego, najkrótszy dopuszczalny czas trwania okna to 10 minut.

Sposoby ustawiania precyzyjnego alarmu

Aplikacja może ustawiać dokładne alarmy za pomocą jednej z tych metod. Metody te są uporządkowane w taki sposób, że te bliżej dołu listy służą do wykonywania zadań bardziej wrażliwych na czas, ale wymagają więcej zasobów systemowych.

setExact()

Wywoływanie alarmu w niemal dokładnym czasie w przyszłości, o ile nie są stosowane inne środki oszczędzania baterii.

Używaj tej metody do ustawiania alarmów precyzyjnych, chyba że działanie aplikacji jest dla użytkownika krytyczne pod względem czasu.

setExactAndAllowWhileIdle()

Wywoływanie alarmu w niemal precyzyjnym czasie w przyszłości, nawet jeśli obowiązują środki oszczędzania baterii.

setAlarmClock()

wywoływać alarm o określonej godzinie w przyszłości; Ponieważ te alarmy są dobrze widoczne dla użytkowników, system nigdy nie dostosowuje czasu ich dostarczania. System rozpoznaje te alarmy jako najważniejsze i w razie potrzeby wyłącza tryby niskiego zużycia energii, aby je dostarczyć.

Zużycie zasobów systemowych

Gdy system wywołuje dokładne alarmy ustawione przez aplikację, urządzenie zużywa dużo zasobów, takich jak bateria, zwłaszcza jeśli jest w trybie oszczędzania energii. Ponadto system nie może łatwo grupować tych żądań, aby efektywniej wykorzystywać zasoby.

Zdecydowanie zalecamy tworzenie niedokładnych alarmów, gdy tylko jest to możliwe. Aby wykonać dłuższą pracę, zaplanuj ją za pomocą funkcji WorkManager lub JobScheduler w alarmie BroadcastReceiver. Aby wykonywać pracę, gdy urządzenie jest w trybie uśpienia, utwórz alarm nieprecyzyjny za pomocą setAndAllowWhileIdle() i uruchom zadanie z alarmu.

Zadeklaruj odpowiednie uprawnienia dostępu do precyzyjnych alarmów

Jeśli Twoja aplikacja jest kierowana na Androida 12 lub nowszego, musisz uzyskać specjalny dostęp do aplikacji „Alarmy i przypomnienia”. Aby to zrobić, zadeklaruj uprawnienie SCHEDULE_EXACT_ALARM w pliku manifestu aplikacji, jak pokazano w tym fragmencie kodu:

<manifest ...>
    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
    <application ...>
        ...
    </application>
</manifest>

Jeśli Twoja aplikacja jest kierowana na Androida 13 (API na poziomie 33) lub nowszego, możesz zadeklarować uprawnienie SCHEDULE_EXACT_ALARM lub USE_EXACT_ALARM.

<manifest ...>
    <uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
    <application ...>
        ...
    </application>
</manifest>

Uprawnienia SCHEDULE_EXACT_ALARMUSE_EXACT_ALARM sygnalizują te same możliwości, ale są przyznawane w inny sposób i obsługują różne przypadki użycia. Aplikacja powinna używać precyzyjnych alarmów i deklarować uprawnienie SCHEDULE_EXACT_ALARM lub USE_EXACT_ALARM tylko wtedy, gdy funkcja aplikacji widoczna dla użytkownika wymaga wykonywania działań w precyzyjnie określonym czasie.

USE_EXACT_ALARM

SCHEDULE_EXACT_ALARM

  • Przyznane przez użytkownika
  • Szerszy zakres zastosowań
  • Aplikacje powinny potwierdzić, że uprawnienia nie zostały cofnięte

Uprawnienie SCHEDULE_EXACT_ALARM nie jest wstępnie przyznawane w przypadku nowych instalacji aplikacji kierowanych na Androida 13 (API na poziomie 33) lub nowszego. Jeśli użytkownik przeniesie dane aplikacji na urządzenie z Androidem 14 w ramach operacji tworzenia i przywracania kopii zapasowej, na nowym urządzeniu zostanie odrzucone uprawnienie SCHEDULE_EXACT_ALARM. Jeśli jednak istniejąca aplikacja ma już to uprawnienie, zostanie ono wstępnie przyznane, gdy urządzenie zostanie zaktualizowane do Androida 14.

Uwaga: jeśli dokładny alarm jest ustawiany za pomocą obiektu OnAlarmListener, np. za pomocą interfejsu API setExact, uprawnienie SCHEDULE_EXACT_ALARM nie jest wymagane.

Korzystanie z uprawnienia SCHEDULE_EXACT_ALARM

W przeciwieństwie do uprawnienia USE_EXACT_ALARM uprawnienie SCHEDULE_EXACT_ALARM musi zostać przyznane przez użytkownika. Zarówno użytkownik, jak i system mogą cofnąć uprawnienie SCHEDULE_EXACT_ALARM.

Aby sprawdzić, czy uprawnienie zostało przyznane aplikacji, przed próbą ustawienia alarmu precyzyjnego wywołaj funkcję canScheduleExactAlarms(). Gdy uprawnienie SCHEDULE_EXACT_ALARM zostanie cofnięte w przypadku Twojej aplikacji, aplikacja przestanie działać, a wszystkie przyszłe alarmy precyzyjne zostaną anulowane. Oznacza to również, że wartość zwracana przez canScheduleExactAlarms() pozostaje ważna przez cały cykl życia aplikacji.

Gdy aplikacja otrzyma uprawnienie SCHEDULE_EXACT_ALARMS, system wyśle do niej transmisję ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED. Aplikacja powinna wdrożyć odbiornik transmisji, który wykonuje te czynności:

  1. Potwierdza, że aplikacja nadal ma specjalny dostęp. Aby to zrobić, zadzwoń pod numer canScheduleExactAlarms(). Ta kontrola chroni aplikację w sytuacji, gdy użytkownik przyzna jej uprawnienia, a następnie niemal natychmiast je cofnie.
  2. Ponownie planuje wszystkie alarmy precyzyjne, których potrzebuje aplikacja, na podstawie jej bieżącego stanu. Ta logika powinna być podobna do tego, co robi aplikacja po otrzymaniu transmisji ACTION_BOOT_COMPLETED.

Proś użytkowników o przyznanie uprawnień SCHEDULE_EXACT_ALARM

Ta opcja nosi nazwę „Zezwalaj na ustawianie alarmów i przypomnień”.
Rysunek 1. „Alarmy i przypomnienia” w ustawieniach systemu, gdzie użytkownicy mogą zezwolić Twojej aplikacji na ustawianie dokładnych alarmów.

W razie potrzeby możesz przekierować użytkowników na ekran Alarmy i przypomnienia w ustawieniach systemu, jak pokazano na ilustracji 1. Aby to zrobić, wykonaj te czynności:

  1. W interfejsie aplikacji wyjaśnij użytkownikowi, dlaczego aplikacja musi planować dokładne alarmy.
  2. Wywołaj intencję, która zawiera działanie intencji ACTION_REQUEST_SCHEDULE_EXACT_ALARM.

Ustawianie alarmu powtarzanego

Powtarzane alarmy umożliwiają systemowi powiadamianie aplikacji zgodnie z powtarzającym się harmonogramem.

Źle zaprojektowany alarm może powodować rozładowywanie baterii i znaczne obciążenie serwerów. Z tego powodu na Androidzie 4.4 (poziom API 19) i nowszym wszystkie powtarzające się alarmy są nieprecyzyjnymi alarmami.

Alarm powtarzający się ma te cechy:

  • Typ alarmu. Więcej informacji znajdziesz w artykule Wybieranie typu alarmu.

  • Czas uruchamiania. Jeśli podasz czas aktywacji z przeszłości, alarm włączy się od razu.

  • interwał alarmu, Możesz na przykład wybrać raz dziennie, co godzinę lub co 5 minut.

  • Oczekująca intencja, która uruchamia się po włączeniu alarmu. Gdy ustawisz drugi alarm, który korzysta z tej samej oczekującej intencji, zastąpi on pierwotny alarm.

Aby anulować PendingIntent(), przekaż FLAG_NO_CREATE do PendingIntent.getService() w celu uzyskania instancji intencji (jeśli istnieje), a następnie przekaż tę intencję do 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)
}

Java

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);
}

Wybieranie typu alarmu

Jedną z pierwszych kwestii, które należy wziąć pod uwagę przy korzystaniu z powtarzającego się alarmu, jest jego typ.

W przypadku alarmów istnieją 2 główne typy zegarów: „czas rzeczywisty, który upłynął” i „zegar czasu rzeczywistego” (RTC). Czas rzeczywisty, który upłynął, używa jako odniesienia „czasu od uruchomienia systemu”, a zegar czasu rzeczywistego używa czasu UTC (zegara ściennego). Oznacza to, że upłynięty czas rzeczywisty nadaje się do ustawiania alarmu na podstawie upływu czasu (np. alarmu, który włącza się co 30 sekund), ponieważ nie ma na niego wpływu strefa czasowa ani ustawienia regionalne. Typ zegara czasu rzeczywistego lepiej nadaje się do alarmów, które zależą od bieżącej lokalizacji.

Oba typy mają wersję „wakeup”, która włącza procesor urządzenia, jeśli ekran jest wyłączony. Dzięki temu alarm włączy się o zaplanowanej godzinie. Jest to przydatne, jeśli Twoja aplikacja jest zależna od czasu. Na przykład jeśli ma ograniczony czas na wykonanie określonej operacji. Jeśli nie używasz wersji alarmu, która ma Cię obudzić, wszystkie powtarzające się alarmy włączą się, gdy urządzenie będzie następnym razem aktywne.

Jeśli alarm ma się włączać w określonych odstępach czasu (np. co pół godziny), użyj jednego z typów czasu rzeczywistego, który upłynął. Ogólnie jest to lepszy wybór.

Jeśli alarm ma się włączać o określonej porze dnia, wybierz jeden z rodzajów zegara czasu rzeczywistego. Pamiętaj jednak, że takie podejście może mieć pewne wady. Aplikacja może nie działać prawidłowo w innych regionach, a jeśli użytkownik zmieni ustawienie czasu na urządzeniu, może to spowodować nieoczekiwane działanie aplikacji. Używanie typu alarmu zegara czasu rzeczywistego również nie jest dobrym rozwiązaniem, o czym wspomnieliśmy powyżej. Jeśli to możliwe, zalecamy używanie alarmu „czas rzeczywisty, który upłynął”.

Oto lista typów:

  • ELAPSED_REALTIME: uruchamia oczekujący zamiar na podstawie czasu, jaki upłynął od uruchomienia urządzenia, ale nie wybudza go. Czas, który upłynął, obejmuje czas, w którym urządzenie było uśpione.

  • ELAPSED_REALTIME_WAKEUP: Wybudza urządzenie i uruchamia oczekujący zamiar po upływie określonego czasu od uruchomienia urządzenia.

  • RTC: uruchamia oczekujący zamiar o określonej godzinie, ale nie wybudza urządzenia.

  • RTC_WAKEUP: wybudza urządzenie, aby uruchomić oczekujący zamiar o określonej godzinie.

Przykłady alarmów czasu rzeczywistego

Oto kilka przykładów użycia ELAPSED_REALTIME_WAKEUP:

Włącz urządzenie, aby alarm włączył się za 30 minut, a potem co 30 minut:

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
)

Java

// 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);

Aby włączyć alarm jednorazowy (niepowtarzający się) za minutę:

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
)

Java

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);

Przykłady alarmów zegara czasu rzeczywistego

Oto kilka przykładów użycia symbolu RTC_WAKEUP.

Włącz urządzenie, aby alarm włączył się około 14:00, i powtarzaj to raz dziennie o tej samej godzinie:

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
)

Java

// 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);

Włącz urządzenie, aby alarm włączył się dokładnie o 8:30, a potem co 20 minut:

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
)

Java

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);

Zdecyduj, jak dokładny ma być alarm

Jak już wspomnieliśmy, wybór typu alarmu jest często pierwszym krokiem podczas tworzenia alarmu. Kolejną różnicą jest wymagana precyzja alarmu. W przypadku większości aplikacji odpowiednią opcją jest setInexactRepeating(). Gdy używasz tej metody, Android synchronizuje wiele nieprecyzyjnych powtarzających się alarmów i uruchamia je w tym samym czasie. Zmniejsza to zużycie baterii.

W miarę możliwości unikaj używania alarmów precyzyjnych. W przypadku rzadkich aplikacji, które mają sztywne wymagania czasowe, możesz jednak ustawić dokładny alarm, wywołując funkcję setRepeating().

W przypadku setInexactRepeating() nie możesz określić niestandardowego przedziału w taki sposób, jak w przypadku setRepeating(). Musisz użyć jednej ze stałych interwału, np. INTERVAL_FIFTEEN_MINUTES, INTERVAL_DAY itd. Pełną listę znajdziesz w AlarmManager.

Anuluj alarm

W zależności od aplikacji możesz dodać możliwość anulowania alarmu. Aby anulować alarm, wywołaj cancel() w usłudze Alarm Manager, przekazując PendingIntent, którego nie chcesz już uruchamiać. Na przykład:

Kotlin

// If the alarm has been set, cancel it.
alarmMgr?.cancel(alarmIntent)

Java

// If the alarm has been set, cancel it.
if (alarmMgr!= null) {
    alarmMgr.cancel(alarmIntent);
}

Uruchamianie alarmu po ponownym uruchomieniu urządzenia

Domyślnie wszystkie alarmy są anulowane, gdy urządzenie się wyłącza. Aby temu zapobiec, możesz zaprojektować aplikację tak, aby automatycznie ponownie uruchamiała powtarzający się alarm, gdy użytkownik ponownie uruchomi urządzenie. Dzięki temu AlarmManager będzie dalej wykonywać swoje zadanie bez konieczności ręcznego ponownego uruchamiania alarmu przez użytkownika.

Aby to zrobić:

  1. Ustaw uprawnienie RECEIVE_BOOT_COMPLETED w pliku manifestu aplikacji. Dzięki temu aplikacja może odbierać sygnał ACTION_BOOT_COMPLETED, który jest emitowany po zakończeniu rozruchu systemu (działa to tylko wtedy, gdy aplikacja została już uruchomiona przez użytkownika co najmniej raz):

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  2. Zaimplementuj element BroadcastReceiver, aby otrzymywać transmisję:

    Kotlin

    class SampleBootReceiver : BroadcastReceiver() {
    
        override fun onReceive(context: Context, intent: Intent) {
            if (intent.action == "android.intent.action.BOOT_COMPLETED") {
                // Set the alarm here.
            }
        }
    }

    Java

    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. Dodaj odbiornik do pliku manifestu aplikacji z filtrem intencji, który filtruje działanie ACTION_BOOT_COMPLETED:

    <receiver android:name=".SampleBootReceiver"
            android:enabled="false">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"></action>
        </intent-filter>
    </receiver>

    Zwróć uwagę, że w pliku manifestu odbiornik rozruchu jest ustawiony na android:enabled="false". Oznacza to, że odbiornik nie zostanie wywołany, chyba że aplikacja wyraźnie go włączy. Zapobiega to niepotrzebnemu wywoływaniu odbiornika rozruchu. Odbiornik możesz włączyć (np. jeśli użytkownik ustawi alarm) w ten sposób:

    Kotlin

    val receiver = ComponentName(context, SampleBootReceiver::class.java)
    
    context.packageManager.setComponentEnabledSetting(
            receiver,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP
    )

    Java

    ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
    PackageManager pm = context.getPackageManager();
    
    pm.setComponentEnabledSetting(receiver,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP);

    Po włączeniu odbiornika w ten sposób pozostanie on włączony, nawet jeśli użytkownik ponownie uruchomi urządzenie. Inaczej mówiąc, programowe włączenie odbiornika zastępuje ustawienie w pliku manifestu, nawet po ponownym uruchomieniu. Odbiornik pozostanie włączony, dopóki aplikacja go nie wyłączy. Odbiornik możesz wyłączyć (np. gdy użytkownik anuluje alarm) w ten sposób:

    Kotlin

    val receiver = ComponentName(context, SampleBootReceiver::class.java)
    
    context.packageManager.setComponentEnabledSetting(
            receiver,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP
    )

    Java

    ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
    PackageManager pm = context.getPackageManager();
    
    pm.setComponentEnabledSetting(receiver,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP);

Wywoływanie alarmów, gdy urządzenie jest w trybie uśpienia

Urządzenia z Androidem 6.0 (poziom interfejsu API 23) obsługują tryb uśpienia, który pomaga wydłużyć żywotność baterii urządzenia. Alarmy nie włączają się, gdy urządzenie jest w trybie uśpienia. Wszystkie zaplanowane alarmy są odkładane do momentu, gdy urządzenie wyjdzie z trybu uśpienia. Jeśli musisz dokończyć pracę, nawet gdy urządzenie jest nieaktywne, masz kilka możliwości:

  • Ustaw dokładny alarm.

  • Używaj interfejsu WorkManager API, który został stworzony do wykonywania zadań w tle. Możesz wskazać, że system ma przyspieszyć pracę, aby zakończyć ją jak najszybciej. Więcej informacji znajdziesz w artykule Planowanie zadań za pomocą WorkManagera.

Sprawdzone metody

Każdy wybór, którego dokonasz podczas projektowania powtarzającego się alarmu, może mieć wpływ na sposób, w jaki aplikacja wykorzystuje (lub nadużywa) zasoby systemowe. Wyobraź sobie na przykład popularną aplikację, która synchronizuje się z serwerem. Jeśli operacja synchronizacji jest oparta na czasie zegarowym i każda instancja aplikacji synchronizuje się o 23:00, obciążenie serwera może spowodować duże opóźnienie lub nawet „odmowę usługi”. Podczas korzystania z alarmów stosuj te sprawdzone metody:

  • Dodaj losowość (jitter) do wszystkich żądań sieciowych, które są wywoływane w wyniku powtarzającego się alarmu:

    • wykonywać lokalne działania po włączeniu alarmu, „Praca lokalna” oznacza wszystko, co nie wymaga dostępu do serwera ani danych z serwera.

    • Jednocześnie zaplanuj alarm, który zawiera żądania sieciowe, tak aby uruchamiał się w losowym przedziale czasu.

  • Ogranicz częstotliwość alarmów do minimum.

  • Nie wybudzaj urządzenia bez potrzeby (to zachowanie zależy od typu alarmu, jak opisano w sekcji Wybieranie typu alarmu).

  • Nie ustawiaj alarmu z dokładnością większą niż jest to konieczne.

    Użyj setInexactRepeating() zamiast setRepeating(). Gdy używasz setInexactRepeating(), Android synchronizuje powtarzające się alarmy z wielu aplikacji i włącza je w tym samym czasie. Dzięki temu zmniejsza się łączna liczba wybudzeń urządzenia przez system, co ogranicza zużycie baterii. Od Androida 4.4 (poziom interfejsu API 19) wszystkie powtarzające się alarmy są niedokładne. Pamiętaj, że choć setInexactRepeating() jest lepszym rozwiązaniem niż setRepeating(), może nadal przeciążać serwer, jeśli każda instancja aplikacji trafi na serwer w tym samym czasie. Dlatego w przypadku żądań sieciowych dodaj do alarmów pewną losowość, jak opisano wcześniej.

  • Jeśli to możliwe, unikaj ustawiania alarmu na podstawie czasu zegarowego.

    Powtarzające się alarmy oparte na dokładnym czasie wywołania nie są dobrze skalowane. Użyj ELAPSED_REALTIME, jeśli to możliwe. Różne rodzaje alarmów opisujemy szczegółowo w następnej sekcji.