Planowanie alarmów

Alarmy (oparte na klasie AlarmManager) umożliwiają wykonywanie operacji zależnych od czasu poza czasem działania aplikacji. Możesz na przykład użyć alarmu do zainicjowania długotrwałej operacji, takiej jak uruchamianie usługi raz dziennie w celu pobrania prognozy pogody.

Alarmy mają te cechy:

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

  • Możesz ich używać w połączeniu z odbiornikami transmisji, aby zaplanować zadania lub WorkRequests, aby wykonywać inne operacje.

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

  • Pomagają one zminimalizować wymagania dotyczące zasobów aplikacji. Możesz zaplanować operacje bez korzystania z zegarów ani usług działających w ciągłym trybie.

Ustawianie nieprecyzyjnego alarmu

Gdy aplikacja ustawi nieprecyzyjny alarm, system wyświetli go w przyszłości. Nieprecyzyjne alarmy zapewniają pewną gwarancję dotyczącą czasu ich wyświetlania, przy jednoczesnym przestrzeganiu ograniczeń dotyczących oszczędzania baterii, takich jak Doze.

Deweloperzy mogą korzystać z tych gwarancji interfejsu API, aby dostosować czas wyświetlania nieprecyzyjnych alarmów.

Wysyłanie alarmu po określonej godzinie

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

W Androidzie 12 (poziom API 31) i nowszych system wywołuje alarm w ciągu 1 godziny od podanego czasu uruchomienia, chyba że obowiązują ograniczenia dotyczące oszczędzania baterii, takie jak tryb oszczędzania baterii czy Doze.

Wysyłanie alarmu w określonym przedziale czasu

Jeśli Twoja aplikacja wywołuje funkcję setWindow(), alarm nigdy nie włączy się przed podanym czasem aktywacji. O ile nie obowiązują żadne ograniczenia dotyczące oszczędzania baterii, alarm jest wysyłany w określonym przedziale czasowym, licząc od określonego czasu aktywacji.

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

wysyłać alarmy powtarzające się w przybliżeniu w regularnych odstępach czasu.

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

  1. Pierwszy alarm włącza się w określonym oknie czasowym, licząc od podanego czasu uruchomienia.
  2. Kolejne alarmy zwykle włączają się po upływie określonego 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 zdarzenia za pomocą nieprecyzyjnych alarmów, aby realizować popularne przypadki użycia. Jeśli główna funkcjonalność aplikacji zależy od alarmu o precyzyjnym czasie, np. w aplikacji budzika lub kalendarza, możesz użyć alarmu precyzyjnego.

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

Poniżej znajdziesz listę typowych procesów, które mogą nie wymagać dokładnego alarmu:

Planowanie operacji związanych z czasowaniem w trakcie działania aplikacji
Klasa Handler zawiera kilka przydatnych metod do obsługi operacji związanych z czasem, takich jak wykonywanie pewnych działań co n sekund podczas działania aplikacji: postAtTime() i postDelayed(). Pamiętaj, że te interfejsy API korzystają z czasu działania systemu, a nie z czasu rzeczywistego.
zaplanowane działanie w tle, takie jak aktualizowanie aplikacji i przesyłanie dzienników;
WorkManager umożliwia planowanie okresowych zadań, które wymagają dokładnego określenia czasu wykonania. Możesz podać interwał powtarzania i flexInterval (co najmniej 15 minut), aby określić szczegółowy czas działania.
Działanie określone przez użytkownika, które powinno nastąpić po określonym czasie (nawet jeśli system jest w stanie bezczynności)
Użyj alarmu nieprecyzyjnego. W szczególności chodzi o numer setAndAllowWhileIdle().
Działanie określone przez użytkownika, które powinno nastąpić po określonym czasie
Użyj alarmu nieprecyzyjnego. W szczególności chodzi o numer set().
Działanie określone przez użytkownika, które może wystąpić w określonym przedziale czasu
Użyj alarmu nieprecyzyjnego. W szczególności chodzi o numer setWindow(). Pamiętaj, że jeśli Twoja aplikacja jest przeznaczona na Androida 12 lub nowszego, minimalna dozwolona długość okna to 10 minut.

Sposoby ustawiania precyzyjnego alarmu

Aplikacja może ustawiać alarmy precyzyjne za pomocą jednej z tych metod. Metody te są uporządkowane w taki sposób, że te, które znajdują się niżej na liście, służą do wykonywania bardziej pilnych zadań, ale wymagają więcej zasobów systemowych.

setExact()

Włączanie alarmu w prawie dokładnym czasie w przyszłości, o ile nie są aktywne inne środki oszczędzania baterii.

Używaj tej metody, aby ustawiać alarmy precyzyjne, chyba że praca aplikacji jest krytyczna dla użytkownika.

setExactAndAllowWhileIdle()

uruchomić alarm w nieco ponad dokładnym czasie w przyszłości, nawet jeśli są aktywne środki oszczędzania baterii;

setAlarmClock()

Uruchom alarm o określonej godzinie w przyszłości. Ponieważ te alarmy są bardzo widoczne dla użytkowników, system nigdy nie zmienia ich czasu dostawy. System rozpoznaje te alarmy jako najważniejsze i w razie potrzeby pozostawia tryby oszczędzania energii, aby je wyświetlić.

Wykorzystanie zasobów systemu

Gdy system uruchamia alarmy ustawione przez aplikację, urządzenie zużywa dużo zasobów, takich jak czas pracy na baterii, 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, aby w miarę możliwości tworzyć nieprecyzyjne alarmy. Aby wykonać dłuższą pracę, zaplanuj ją za pomocą WorkManager lub JobScheduler z BroadcastReceiver alarmu. Aby wykonywać zadania, gdy urządzenie jest w trybie Doze, utwórz alarm nieprecyzyjny za pomocą setAndAllowWhileIdle() i uruchom zadanie z alarmu.

Zadeklaruj odpowiednie uprawnienie 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ć, w pliku manifestu aplikacji zadeklaruj uprawnienie SCHEDULE_EXACT_ALARM, 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>

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

USE_EXACT_ALARM

SCHEDULE_EXACT_ALARM

  • Udzielone przez użytkownika
  • szerszy zakres zastosowań,
  • Aplikacje powinny potwierdzać, że uprawnienia nie zostały cofnięte

Uprawnienie SCHEDULE_EXACT_ALARM nie jest przyznawane wstępnie w przypadku świeżo zainstalowanych aplikacji kierowanych na Androida 13 (poziom API 33) lub nowszego. Jeśli użytkownik przeniesie dane aplikacji na urządzenie z Androidem 14, korzystając z operacji tworzenia i przywracania kopii zapasowej, na nowym urządzeniu zostanie odrzucone uprawnienie SCHEDULE_EXACT_ALARM. Jeśli jednak dana aplikacja ma już to uprawnienie, zostanie ono wstępnie przyznane, gdy urządzenie zostanie uaktualnione do Androida 14.

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

Używanie uprawnienia SCHEDULE_EXACT_ALARM

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

Aby sprawdzić, czy Twoja aplikacja ma to uprawnienie, przed użyciem alarmu precyzyjnego wywołaj funkcję canScheduleExactAlarms(). Gdy uprawnienia SCHEDULE_EXACT_ALARM zostaną cofnięte, aplikacja przestanie działać, a wszystkie przyszłe alarmy precyzyjne zostaną anulowane. Oznacza to też, że wartość zwracana przez funkcję canScheduleExactAlarms() pozostaje prawidłowa przez cały cykl życia aplikacji.

Gdy aplikacja uzyska uprawnienia SCHEDULE_EXACT_ALARMS, system prześle jej transmisję ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED. Aplikacja powinna implementować odbiornik rozgłoszeniowy, który:

  1. Potwierdza, że Twoja aplikacja nadal ma dostęp specjalny. Aby to zrobić, zadzwoń pod numer canScheduleExactAlarms(). Ta weryfikacja chroni aplikację przed sytuacją, gdy użytkownik przyzna jej uprawnienie, a następnie prawie natychmiast je cofnie.
  2. Przekłada wszystkie alarmy precyzyjne, których potrzebuje aplikacja, na podstawie jej bieżącego stanu. Ta logika powinna być podobna do tej, którą aplikacja wykonuje po otrzymaniu ACTION_BOOT_COMPLETEDtransmisji.

Zapytaj użytkowników o przyznanie uprawnień SCHEDULE_EXACT_ALARM

Opcja nosi nazwę „Zezwalaj na ustawianie alarmów i przypomnień”.
Rysunek 1. „Alarmy i przypomnienia” na stronie dostępu aplikacji w ustawieniach systemu, gdzie użytkownicy mogą zezwolić aplikacji na ustawianie alarmów.

W razie potrzeby możesz wysłać użytkowników na ekran Budziki i przypomnienia w ustawieniach systemu, jak pokazano na rysunku 1. Aby to zrobić:

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

Ustawianie alarmu powtarzającego się

Alarmy powtarzające się pozwalają systemowi wysyłać powiadomienia do aplikacji zgodnie z określonym harmonogramem.

Źle zaprojektowany alarm może rozładowywać baterię i znacznie obciążać serwery. Z tego powodu na Androidzie 4.4 (poziom interfejsu API 19) i nowszych wszystkie alarmy powtarzające się są nieprecyzyjne.

Alarm powtarzający ma te cechy:

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

  • Czas aktywacji. Jeśli podany przez Ciebie czas jest w przeszłości, alarm zostanie uruchomiony natychmiast.

  • Interwał alarmu. Na przykład raz dziennie, co godzinę lub co 5 minut.

  • Oczekująca intencja, która jest wywoływana po uruchomieniu alarmu. Gdy ustawisz drugi alarm, który używa tego samego oczekującego zamiaru, zastąpi on pierwotny alarm.

Aby anulować PendingIntent(), prześlij FLAG_NO_CREATE do PendingIntent.getService(), aby uzyskać instancję inencji (jeśli istnieje), a następnie prześlij 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

Jednym z pierwszych czynników, które należy wziąć pod uwagę przy używaniu alarmu powtarzającego, jest jego typ.

Istnieją 2 ogólne typy zegara alarmowego: „upływający czas rzeczywisty” i „zegar czasu rzeczywistego” (RTC). Upływający czas rzeczywisty używa jako odniesienia „czasu od uruchomienia systemu”, a zegar czasu rzeczywistego używa czasu UTC (zegar ścienny). Oznacza to, że upływający czas rzeczywisty jest odpowiedni do ustawiania alarmu na podstawie upływu czasu (na przykład alarmu, który działa co 30 sekund), ponieważ nie jest on zależny od strefy czasowej ani lokalizacji. Typ zegara w czasie rzeczywistym jest bardziej odpowiedni w przypadku alarmów zależnych od bieżących ustawień regionalnych.

Oba typy mają wersję „budzenia”, która powoduje wybudzenie procesora urządzenia, jeśli ekran jest wyłączony. Dzięki temu alarm zostanie uruchomiony o zaplanowanej godzinie. Jest to przydatne, gdy aplikacja ma zależność czasową. Na przykład, jeśli ma ograniczony czas na wykonanie określonej operacji. Jeśli nie używasz wersji alarmu z budzeniem, wszystkie alarmy powtarzające będą się włączać, gdy urządzenie będzie się włączać.

Jeśli po prostu chcesz, aby alarm był uruchamiany w określonym odstępie czasu (np. co pół godziny), użyj jednego z typów czasu upływającego w czasie rzeczywistym. Zazwyczaj jest to lepszy wybór.

Jeśli chcesz, aby alarm włączał się o określonej porze dnia, wybierz jeden z typów zegara opartego na czasie rzeczywistym. Pamiętaj jednak, że takie podejście może mieć pewne wady. Aplikacja może nie działać prawidłowo w innych lokalizacjach, a jeśli użytkownik zmieni ustawienia czasu na urządzeniu, może to spowodować nieoczekiwane działanie aplikacji. Jak już wspomnieliśmy, użycie typu alarmu zegarka w czasie rzeczywistym nie jest też zbyt elastyczne. Jeśli to możliwe, zalecamy używanie alarmu „upływający rzeczywisty czas”.

Oto lista typów:

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

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

  • RTC: uruchamia oczekujący zamiar we wskazanym czasie, ale nie wybudza urządzenia.

  • RTC_WAKEUP: wybudza urządzenie, aby w określonym czasie uruchomić oczekujący zamiar.

Przykłady alarmów w czasie rzeczywistym

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

Włącz urządzenie, aby włączyć alarm co 30 minut i co 30 minut po tym czasie:

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 uruchomić alarm jednorazowy (niepowtarzalny) w ciągu minuty:

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 budzików w czasie rzeczywistym

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

Włącz urządzenie, aby włączyć alarm o godzinie około 14:00 i powtarzaj tę czynność raz dziennie o tej samej porze:

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

Uruchom urządzenie, aby włączyć alarm dokładnie o 8:30 i 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 w procesie tworzenia alarmu. Kolejna różnica to dokładność alarmu. W przypadku większości aplikacji odpowiednia jest opcja setInexactRepeating(). Gdy używasz tej metody, Android synchronizuje wiele nieprecyzyjnych alarmów powtarzających i uruchamia je w tym samym czasie. Pozwala to zmniejszyć zużycie baterii.

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

W przypadku setInexactRepeating() nie możesz określić niestandardowego przedziału czasowego w sposób, w jaki możesz to zrobić w przypadku setRepeating(). Musisz użyć jednej z interwałowych stałych, np. INTERVAL_FIFTEEN_MINUTES, INTERVAL_DAY itd. Pełną listę znajdziesz na stronie AlarmManager.

Anuluj alarm

W zależności od aplikacji możesz dodać możliwość anulowania alarmu. Aby anulować alarm, wywołaj funkcję cancel() w menedżerze alarmów, przekazując parametr PendingIntent, którego nie chcesz już uruchamiać. 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);
}

Uruchom alarm po ponownym uruchomieniu urządzenia

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

Aby to zrobić:

  1. W pliku manifestu aplikacji ustaw uprawnienie RECEIVE_BOOT_COMPLETED. Pozwala to aplikacji na odbieranie ACTION_BOOT_COMPLETED, który jest transmitowany po zakończeniu rozruchu systemu (działa to tylko wtedy, gdy aplikacja została już co najmniej raz uruchomiona przez użytkownika):

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  2. Aby odbierać transmisję, zainstaluj: BroadcastReceiver

    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 za pomocą filtra intencji, który filtruje według działania 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 uruchamiania ma wartość android:enabled="false". Oznacza to, że odbiorca nie zostanie wywołany, chyba że aplikacja wyraźnie to umożliwi. Zapobiega to niepotrzebnemu wywoływaniu odbiornika uruchamiania. Aby włączyć odbiornik (np. jeśli użytkownik ustawia alarm), wykonaj te czynności:

    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 zrestartuje urządzenie. Inaczej mówiąc, programowe włączenie odbiornika zastąpi ustawienie w pliku manifestu nawet po ponownym uruchomieniu. Odbiornik pozostanie włączony, dopóki aplikacja go nie wyłączy. Aby wyłączyć odbiornik (np. jeśli użytkownik anuluje alarm), wykonaj te czynności:

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

Uruchom alarmy, gdy urządzenie jest w trybie Doze

Urządzenia z Androidem 6.0 (poziom interfejsu API 23) obsługują tryb Doze, który wydłuża czas pracy baterii. Alarmy nie są włączane, gdy urządzenie jest w trybie Doze. Wszystkie zaplanowane alarmy są opóźniane do czasu, aż urządzenie wyjdzie z trybu Doze. Jeśli chcesz wykonać zadanie, gdy urządzenie jest nieaktywne, masz do wyboru kilka opcji:

  • Ustaw dokładny alarm.

  • Użyj interfejsu WorkManager API, który został stworzony do wykonywania zadań w tle. Możesz wskazać, że system powinien przyspieszyć Twoją pracę, aby została ukończona jak najszybciej. Więcej informacji znajdziesz w artykule Planowanie zadań za pomocą WorkManager.

Sprawdzone metody

Każdy wybór dokonany podczas projektowania alarmu powtarzającego się może mieć wpływ na to, jak 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 i każdy egzemplarz aplikacji synchronizuje się o 23:00, obciążenie serwera może spowodować duże opóźnienie lub nawet odmowę usługi. Stosuj te sprawdzone metody dotyczące alarmów:

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

    • wykonywać jakiekolwiek działania lokalne po uruchomieniu alarmu. „Praca lokalna” to wszystko, co nie wymaga korzystania z serwera ani przesyłania danych na serwer.

    • W tym samym czasie zaplanuj alarm, który zawiera żądania sieci, aby były wykonywane w losowym przedziale czasu.

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

  • Nie budź urządzenia bez potrzeby (to zachowanie jest określane przez typ alarmu, jak opisano w sekcji Wybieranie typu alarmu).

  • Nie ustawiaj czasu aktywacji alarmu na bardziej precyzyjny niż to konieczne.

    Zamiast setRepeating() użyj setInexactRepeating(). Gdy używasz setInexactRepeating(), Android synchronizuje alarmy powtarzające się z kilku aplikacji i uruchamia je jednocześnie. Dzięki temu system musi uruchamiać urządzenie mniej razy, co zmniejsza zużycie baterii. Od Androida 4.4 (poziom interfejsu API 19) wszystkie alarmy powtarzające się są nieprecyzyjne. Pamiętaj, że chociaż setInexactRepeating() jest lepszym rozwiązaniem niż setRepeating(), to nadal może przeciążyć serwer, jeśli każda instancja aplikacji łączy się z serwerem w przybliżeniu w tym samym czasie. Dlatego w przypadku żądań sieciowych dodaj do swoich alarmów pewną losowość, jak opisano wcześniej.

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

    Alarmy powtarzające się, które są oparte na dokładnym czasie aktywacji, nie skalują się dobrze. Jeśli to możliwe, używaj formatu ELAPSED_REALTIME. W następnej sekcji znajdziesz więcej informacji o różnych typach alarmów.