Planowanie alarmów

Alarmy (oparte na klasie AlarmManager) umożliwiają wykonywanie operacji zależnych od czasu poza czasem działania aplikacji. Alarmu możesz na przykład użyć do zainicjowania długotrwałej operacji, takiej jak uruchamianie usługi raz dziennie, aby pobrać prognozę pogody.

Alarmy mają te cechy:

  • Umożliwiają uruchamianie intencji o określonych porach lub w określonych odstępach czasu.

  • Możesz ich używać w połączeniu z odbiornikami do planowania zadań lub WorkRequests do wykonywania innych operacji.

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

  • Pomagają one zminimalizować wymagania dotyczące zasobów aplikacji. Możesz planować operacje bez polegania na licznikach czasu ani nieprzerwanie działających usług.

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 aplikacja wywołuje 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 1 godziny od podanego czasu uruchomienia, chyba że obowiązują ograniczenia dotyczące oszczędzania baterii, takie jak Oszczędzanie 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. Jeśli nie są stosowane żadne ograniczenia oszczędzania baterii, alarm jest dostarczany w określonym przedziale czasu, zaczynając od podanego czasu aktywacji.

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

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

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

  1. Pierwszy alarm włącza się w określonym oknie czasowym, licząc od podanego czasu uruchomienia.
  2. Kolejne alarmy zwykle są włączane 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.

Przypadki użycia, 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 prace 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 zostać wykonane 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 zostać wykonane 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 dokładnego alarmu

Aplikacja może ustawiać alarmy precyzyjne za pomocą jednej z tych metod. Metody są uporządkowane w taki sposób, że te znajdujące się bliżej dołu listy obsługują zadania o większym znaczeniu czasowym, 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()

Wywołuj alarm w przyszłości niemal z dokładnością, nawet jeśli masz włączone oszczędzanie baterii.

setAlarmClock()

Uruchom alarm o określonej godzinie w przyszłości. Ponieważ te alarmy są dobrze widoczne dla użytkowników, system nigdy nie dostosowuje czasu działania. 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 aktywuje alarm precyzyjny ustawiony przez aplikację, urządzenie zużywa dużo zasobów, np. żywotność baterii, zwłaszcza w trybie oszczędzania energii. Ponadto system nie może łatwo grupować tych żądań, aby efektywniej wykorzystywać zasoby.

Zdecydowanie zalecamy utworzenie alarmu precyzyjnego, gdy jest to możliwe. Aby wykonać dłuższą pracę, zaplanuj ją za pomocą WorkManager lub JobScheduler z poziomu alarmu BroadcastReceiver. 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ć alarmów precyzyjnych i zadeklarować uprawnienie SCHEDULE_EXACT_ALARM lub USE_EXACT_ALARM tylko wtedy, gdy funkcja dostępna dla użytkownika w aplikacji 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 w ramach operacji tworzenia i przywracania kopii zapasowej, na nowym urządzeniu zostanie odmówione uprawnienie SCHEDULE_EXACT_ALARM. Jeśli jednak istniejąca aplikacja ma już to uprawnienie, zostanie ono wstępnie przyznane przy przejściu na 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. 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 uprawnienie SCHEDULE_EXACT_ALARM zostanie anulowane dla aplikacji, 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. W aplikacji musisz wdrożyć odbiornik, który:

  1. Potwierdza, że Twoja aplikacja nadal ma dostęp specjalny. Aby to zrobić, zadzwoń na numer canScheduleExactAlarms(). Ta weryfikacja chroni aplikację przed sytuacją, w której użytkownik przyzna uprawnienia, a następnie 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ę zawierającą działanie ACTION_REQUEST_SCHEDULE_EXACT_ALARM.

Ustawianie alarmu powtarzającego się

Powtarzające się alarmy umożliwiają systemowi powiadamianie aplikacji w sposób cykliczny.

Źle zaprojektowany alarm może rozładować baterię i znacznie obciążyć serwery. Dlatego w Androidzie 4.4 (poziom interfejsu API 19) i nowszych wszystkie powtarzające się alarmy są alarmami nieprecyzyjnymi.

Alarm powtarzający ma te cechy:

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

  • Czas wyzwalania. 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 wykonywana po uruchomieniu alarmu. Gdy ustawisz drugi alarm, który korzysta z tej samej oczekującej intencji, zastąpi on pierwotny alarm.

Aby anulować PendingIntent(), prześlij FLAG_NO_CREATE do PendingIntent.getService(), aby uzyskać instancję intencji (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). Czas rzeczywisty jest używany jako wartość referencyjna „czas od uruchomienia systemu”, a zegar czasu rzeczywistego używa czasu UTC (zegara ściennego). 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ę „wybudzanie”, która polega na wybudzeniu procesora urządzenia, gdy ekran jest wyłączony. Dzięki temu alarm uruchomi się o zaplanowanej godzinie. Jest to przydatne, jeśli aplikacja ma zależność czasową. Może to być np. ograniczona ilość czasu, w którym można wykonać konkretną operację. Jeśli nie użyjesz wersji typu wybudzenia, wszystkie powtarzające się alarmy zostaną uruchomione, gdy urządzenie zostanie wybudzone.

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 uruchomił się o określonej porze dnia, wybierz jeden z typów zegara czasu rzeczywistego opartych na zegarze. Pamiętaj jednak, że takie podejście może mieć pewne wady. Aplikacja może nie tłumaczyć prawidłowo na inne języki, a jeśli użytkownik zmieni ustawienie czasu na urządzeniu, może to spowodować nieoczekiwane działanie aplikacji. Korzystanie z budzika zegara w czasie rzeczywistym również nie skaluje się, jak opisano powyżej. Jeśli to możliwe, zalecamy używanie alarmu „upływający czas rzeczywisty”.

Oto lista typów:

  • ELAPSED_REALTIME: uruchamia oczekujący zamiar na podstawie czasu od momentu uruchomienia urządzenia, ale nie wybudza go. 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 wywołać oczekujący zamiar we wskazanym czasie.

Przykłady alarmów w czasie rzeczywistym

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

Wybudź urządzenie 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 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);

Wybudź urządzenie, aby alarm uruchomił się 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. Dzięki temu bateria szybciej się nie rozładowuje.

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

Za pomocą setInexactRepeating() nie możesz określić niestandardowego interwału w taki sam sposób jak 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 warto dodać opcję anulowania alarmu. Aby anulować alarm, wywołaj funkcję cancel() w klasie AlarmManager, przekazując parametr PendingIntent, który nie ma już działać. 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);
}

Włącz 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. Ustaw uprawnienie RECEIVE_BOOT_COMPLETED w pliku manifestu aplikacji. 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 odbiorcę do pliku manifestu aplikacji za pomocą filtra 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 uruchamiania ma wartość android:enabled="false". Oznacza to, że odbiorca nie zostanie wywołany, dopóki aplikacja tego nie włączy. Zapobiega to niepotrzebnemu wywoływaniu odbiornika uruchamiania. Odbiornik możesz włączyć (na przykład wtedy, gdy 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 zrestartuje 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. jeśli 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);

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 alarm precyzyjny.

  • Użycie interfejsu WorkManager API przeznaczonego do pracy 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, którego podejmujesz przy projektowaniu powtarzających się alarmów, 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 bazuje na czasie zegara, a każda instancja aplikacji synchronizuje się o 23:00, obciążenie serwera może skutkować dużymi opóźnieniami, a 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.

  • Dopilnuj, aby częstotliwość alarmu była jak najmniejsza.

  • 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ż jest 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ż wersja setInexactRepeating() jest lepsza niż setRepeating(), nadal może spowodować przeciążenie serwera, jeśli każda instancja aplikacji trafi na serwer w tym samym czasie. Dlatego w przypadku żądań sieciowych zwiększ losowość alarmów, jak to opisaliśmy 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. Typy alarmów opisujemy bardziej szczegółowo w następnej sekcji.