Planowanie alarmów

Alarmy (oparte na klasie AlarmManager) umożliwiają wykonywanie operacji opartych na czasie poza okresem aktywności 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ą następujące cechy:

  • Umożliwiają uruchamianie intencji w ustalonych odstępach czasu 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łają one poza Twoją aplikacją, więc możesz ich używać do wywoływania zdarzeń lub działań nawet wtedy, gdy aplikacja nie jest uruchomiona, a urządzenie jest uśpione.

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

Ustaw alarm niedokładny

Gdy aplikacja ustawi alarm nieprecyzyjny, system w pewnym momencie włączy alarm. Alarmy nieprecyzyjne dają pewne gwarancje w zakresie czasu włączenia alarmu z uwzględnieniem ograniczeń pozwalających oszczędzać baterię, takich jak Uśpienie.

Deweloperzy mogą wykorzystać poniższe gwarancje interfejsu API, aby dostosować czas dostarczania nieprecyzyjnego alarmu.

Włącz alarm 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 interfejsu API 31) i nowszych system wywołuje alarm w ciągu 1 godziny od podanego czasu aktywacji, chyba że są włączone jakiekolwiek ograniczenia dotyczące oszczędzania baterii, takie jak oszczędzanie baterii lub sjesta.

Dostarcz alarm w wybranym przedziale czasu

Jeśli aplikacja wywoła metodę setWindow(), alarm nigdy nie włączy się przed podanym czasem wywołania. 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 kierowana na Androida 12 lub nowszego, system może opóźnić wywołanie nieprecyzyjnego alarmu z wyznaczonym przedziałem czasu o co najmniej 10 minut. Z tego powodu wartości parametrów windowLengthMillis w polu 600000 zostały przypięte do 600000.

Uruchamiaj powtarzający się alarm w mniej więcej regularnych odstępach czasu

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

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

Ustaw dokładny alarm

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

Większość aplikacji może planować zadania i wydarzenia za pomocą alarmów nieprecyzyjnych w kilku typowych przypadkach użycia. Jeśli główna funkcjonalność aplikacji zależy od konkretnego alarmu (np. budzika lub aplikacji kalendarza), możesz zamiast tego użyć alarmu precyzyjnego.

Przypadki użycia, które mogą nie wymagać alarmów precyzyjnych

Na liście poniżej znajdziesz typowe przepływy pracy, które mogą nie wymagać dokładnego alarmu:

Planowanie operacji czasowych w trakcie użytkowania aplikacji
Klasa Handler zawiera kilka dobrych metod obsługi operacji czasowych, np. wykonywanie pewnych działań co n sekund, gdy aplikacja jest aktywna: postAtTime() i postDelayed(). Pamiętaj, że te interfejsy API zależą od czasu działania systemu, a nie od czasu rzeczywistego.
zaplanowane prace w tle, takie jak aktualizowanie aplikacji i przesyłanie dzienników;
WorkManager umożliwia planowanie okresowych zadań uzależnionych od czasu. Możesz podać interwał powtarzania i flexInterval (co najmniej 15 minut), aby zdefiniować szczegółowe czasy wykonywania pracy.
Działanie określone przez użytkownika, które powinno zostać wykonane po określonym czasie (nawet jeśli system jest nieaktywny)
Użyj alarmu nieprecyzyjnego. a konkretnie – wywołaj setAndAllowWhileIdle().
Działanie określone przez użytkownika, które powinno zostać wykonane po określonym czasie
Użyj alarmu nieprecyzyjnego. a konkretnie – wywołaj set().
Działanie określone przez użytkownika, które może zostać wykonane w określonym przedziale czasu
Użyj alarmu nieprecyzyjnego. a konkretnie – wywołaj setWindow(). Jeśli aplikacja jest kierowana na Androida 12 lub nowszego, najniższa dopuszczalna długość okna to 10 minut.

Sposoby ustawiania dokładnego alarmu

Aplikacja może ustawiać alarmy precyzyjne za pomocą jednej z poniższych 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()

Wywołaj alarm w niemal dokładnym czasie w przyszłości, o ile nie zostaną zastosowane inne sposoby oszczędzania baterii.

Użyj tej metody, aby ustawić alarmy precyzyjne, chyba że praca w aplikacji ma kluczowe znaczenie 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()

Wywołaj alarm w konkretnym czasie w przyszłości. Ponieważ te alarmy są dobrze widoczne dla użytkowników, system nigdy nie dostosowuje czasu działania. System określa te alarmy jako najważniejsze i w razie potrzeby pozostawia tryby niskiego zużycia energii.

Wykorzystanie zasobów systemowych

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. System nie może też łatwo grupować tych żądań, aby efektywniej korzystać z zasobów.

Zdecydowanie zalecamy utworzenie alarmu precyzyjnego, gdy jest to możliwe. Aby wykonać dłuższą pracę, zaplanuj ją za pomocą opcji WorkManager lub JobScheduler na alarmie BroadcastReceiver. Aby wykonać pracę, gdy urządzenie jest w trybie uśpienia, utwórz nieprecyzyjny alarm przy użyciu setAndAllowWhileIdle() i uruchom zadanie od 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 (poziom interfejsu API 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_ALARM i USE_EXACT_ALARM sygnalizują te same możliwości, są one przyznawane w różny sposób i mają różne zastosowania. 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

  • Przyznane przez użytkownika
  • Szerszy zestaw przypadków użycia
  • Aplikacja powinna potwierdzić, że uprawnienia nie zostały cofnięte.

Uprawnienie SCHEDULE_EXACT_ALARM nie jest wstępnie przyznawane nowym instalacjom aplikacji kierowanych na Androida 13 (poziom interfejsu API 33) i nowsze wersje. 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 po przejściu na Androida 14.

Uwaga: jeśli dokładny alarm jest ustawiony 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 zasady USE_EXACT_ALARM uprawnienie SCHEDULE_EXACT_ALARM musi być przyznane przez użytkownika. Uprawnienia SCHEDULE_EXACT_ALARM mogą unieważnić zarówno użytkownik, jak i system.

Aby sprawdzić, czy aplikacja otrzymała odpowiednie uprawnienia, wywołaj canScheduleExactAlarms() przed próbą ustawienia dokładnego alarmu. Gdy uprawnienie SCHEDULE_EXACT_ALARM zostanie odebrane aplikacji, aplikacja przestanie działać, a wszystkie przyszłe alarmy precyzyjne zostaną anulowane. Oznacza to również, że wartość zwracana przez funkcję canScheduleExactAlarms() jest ważna przez cały cykl życia aplikacji.

Gdy aplikacja otrzyma uprawnienie SCHEDULE_EXACT_ALARMS, system wyśle ją do transmisji ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED. W aplikacji musisz wdrożyć odbiornik, który:

  1. potwierdza, że aplikacja nadal ma uprawnienia dostępu do określonych aplikacji. Aby to zrobić, wywołaj canScheduleExactAlarms(). Dzięki temu możesz chronić aplikację przed sytuacją, w której użytkownik przyznał jej uprawnienia, a następnie prawie natychmiast je anuluje.
  2. Zmienia terminy alarmów precyzyjnych, których potrzebuje aplikacja, na podstawie jej bieżącego stanu. Ta logika powinna być podobna do działania aplikacji, która odbiera transmisję ACTION_BOOT_COMPLETED.

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

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

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

  1. W interfejsie aplikacji wyjaśnij użytkownikowi, dlaczego aplikacja musi ustawiać harmonogram precyzyjnych alarmów.
  2. Wywołaj intencję zawierającą działanie intencji ACTION_REQUEST_SCHEDULE_EXACT_ALARM.

Ustawianie powtarzania alarmu

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.

Powtarzające się alarmy mają następujące cechy:

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

  • Czas wyzwalania. Jeśli podany czas wyzwolenia przypada w przeszłości, alarm uruchomi się natychmiast.

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

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

Aby anulować PendingIntent(), przekaż działanie FLAG_NO_CREATE do PendingIntent.getService() w celu uzyskania wystąpienia 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);
}

Wybierz typ alarmu

Jednym z pierwszych kwestii, które należy wziąć pod uwagę podczas używania powtarzających się alarmów, jest jego typ.

Istnieją 2 główne typy zegara do alarmów: „Czas rzeczywisty” i „Zegar w czasie rzeczywistym” (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 możesz ustawić alarm na podstawie upływu czasu (np. alarm, który uruchamia się co 30 sekund), ponieważ strefa czasowa ani język nie mają na niego wpływu. Zegar w czasie rzeczywistym lepiej sprawdza się w przypadku alarmów zależnych od regionu.

Oba typy mają wersję „wybudzenie”, 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ą. Chodzi np. o ograniczenie czasu na wykonanie konkretnej operacji. Jeśli nie użyjesz wersji typu wybudzenia, wszystkie powtarzające się alarmy zostaną uruchomione, gdy urządzenie zostanie wybudzone.

Jeśli chcesz, aby alarm uruchamiał się w określonych odstępach czasu (np. co pół godziny), użyj jednego z rodzajów czasu rzeczywistego, który upłynął. Ogólnie 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. Takie podejście może jednak 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 z zegarem w czasie rzeczywistym również nie skaluje się, jak opisano powyżej. Zalecamy, aby w miarę możliwości używać alarmu typu „Upłynęło w czasie rzeczywistym”.

Oto lista typów:

  • ELAPSED_REALTIME: uruchamia oczekującą intencję na podstawie czasu, który upłynął od uruchomienia urządzenia, ale go nie wybudza. Upływ czasu obejmuje każdy okres uśpienia urządzenia.

  • ELAPSED_REALTIME_WAKEUP: wybudza urządzenie i uruchamia intencję oczekującą po upływie określonego czasu od uruchomienia urządzenia.

  • RTC: uruchamia oczekującą intencję w określonym czasie, ale nie wybudza urządzenia.

  • RTC_WAKEUP: wybudza urządzenie, aby uruchomić intencję oczekującą o określonej godzinie.

Przykłady alarmów upływających w czasie rzeczywistym

Oto kilka przykładów użycia 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);

Wybudź urządzenie w ciągu minuty, aby uruchomić jednorazowy (niepowtarzający się) alarm:

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

Oto kilka przykładów użycia właściwości RTC_WAKEUP.

Wybudź urządzenie, aby wybudzić alarm około około 14:00, i powtarzaj go 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);

Określ, jak dokładny ma być alarm

Jak już wspomnieliśmy, wybór typu alarmu jest często pierwszym krokiem przy tworzeniu alarmu. Kolejną różnicą jest to, jak precyzyjne ma być alarm. W przypadku większości aplikacji odpowiedni wybór to setInexactRepeating(). Gdy używasz tej metody, Android synchronizuje wiele nieprecyzyjnie powtarzanych alarmów i uruchamia je jednocześnie. Zmniejszy to zużycie baterii.

W miarę możliwości unikaj 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 ze stałych odstępów, np. INTERVAL_FIFTEEN_MINUTES, INTERVAL_DAY itd. Pełną listę znajdziesz tutaj: AlarmManager.

Anuluj alarm

W zależności od aplikacji warto dodać opcję anulowania alarmu. Aby anulować alarm, wywołaj cancel() w Menedżerze alarmów, podają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);
}

Włącz alarm po ponownym uruchomieniu urządzenia

Domyślnie wszystkie alarmy są anulowane po wyłączeniu urządzenia. Aby temu zapobiec, możesz zaprojektować aplikację tak, aby automatycznie uruchamiała powtarzający się alarm, gdy użytkownik ponownie uruchomi urządzenie. Dzięki temu AlarmManager będzie kontynuować 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 otrzymywać ACTION_BOOT_COMPLETED, które jest wysyłane po zakończeniu rozruchu systemu (działa tylko wtedy, gdy użytkownik co najmniej raz uruchomił aplikację):

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  2. Zaimplementuj BroadcastReceiver do odbierania transmisji:

    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 manifeście odbiornik jest ustawiony na android:enabled="false". Oznacza to, że odbiorca nie zostanie wywołany, dopóki aplikacja go nie włączy. Zapobiega to niepotrzebnemu wywoływaniu odbiornika. 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);
    

    Gdy włączysz w ten sposób odbiornik, pozostanie on włączony, nawet jeśli użytkownik zrestartuje urządzenie. Inaczej mówiąc, automatyczne włączenie odbiornika zastępuje ustawienie w pliku manifestu, nawet po ponownym uruchomieniu. Odbiorca 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);
    

Wywołuj alarmy, gdy urządzenie jest w trybie uśpienia

Urządzenia z Androidem 6.0 (poziom interfejsu API 23) obsługują tryb Uśpienie, który pomaga wydłużyć czas pracy na baterii. Alarmy nie są uruchamiane, gdy urządzenie jest w trybie uśpienia Wszystkie zaplanowane alarmy są odłożone do momentu wyjściu urządzenia z trybu uśpienia. Jeśli chcesz wykonać pracę nawet wtedy, gdy urządzenie jest bezczynne, masz do wyboru kilka opcji:

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źmy sobie np. popularną aplikację synchronizującą 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”. Postępuj zgodnie z tymi sprawdzonymi metodami używania alarmów:

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

    • Po uruchomieniu alarmu wykonaj dowolną pracę lokalną. „Praca lokalna” oznacza wszystko, co nie ma dostępu do serwera i nie wymaga danych z serwera.

    • Jednocześnie zaplanuj alarm, który zawiera żądania sieciowe, w losowym czasie.

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

  • Nie wybudzaj urządzenia niepotrzebnie (to działanie zależy od typu alarmu, zgodnie z opisem w sekcji Wybieranie typu alarmu).

  • Nie ustawiaj dokładnej godziny włączenia alarmu.

    Używaj setInexactRepeating() zamiast setRepeating(). Gdy używasz setInexactRepeating(), Android synchronizuje powtarzające się alarmy z wielu aplikacji i włącza je jednocześnie. Pozwala to zmniejszyć całkowitą liczbę przypadków wybudzania urządzenia przez system, a tym samym mniejsze zużycie baterii. Od Androida 4.4 (poziom interfejsu API 19) wszystkie powtarzające się alarmy są alarmami nieprecyzyjnymi. 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.

  • W miarę możliwości unikaj używania budzika na podstawie godziny.

    Powtarzające się alarmy oparte na dokładnym czasie aktywacji nie są dobrze skalowane. Jeśli to możliwe, użyj ELAPSED_REALTIME. Typy alarmów opisujemy bardziej szczegółowo w następnej sekcji.