Planowanie alarmów

Alarmy (na podstawie klasy AlarmManager) umożliwiają wykonywanie operacji na określonym czasie poza okresem trwania aplikacji. Możesz na przykład użyć alarmu, aby rozpocząć długotrwałą operację, taką jak uruchomienie usługi raz dziennie w celu pobrania prognozy pogody.

Alarmy mają następujące cechy:

  • Pozwalają uruchamiać intencje o określonych porach lub w określonych odstępach czasu.

  • Możesz ich używać razem z odbiornikami, aby planować zadania lub żądania robocze 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 i nawet jeśli urządzenie jest uśpione.

  • Pomagają one zminimalizować wymagania aplikacji dotyczące zasobów. Możesz planować operacje bez stosowania liczników czasu ani ciągłego działania usług.

Ustaw alarm niedokładny

Gdy aplikacja ustawi niedokładny alarm, system uruchomi go w przyszłości. Alarmy nieprecyzyjne dają gwarancję czasu dostarczania alarmu przy jednoczesnym zachowaniu zgodności z ograniczeniami dotyczącymi oszczędzania baterii, takimi jak uśpienie.

Deweloperzy mogą skorzystać z opisanych poniżej gwarancji interfejsu API, aby dostosować czas dostarczania niedokładnego alarmu.

Dostarczenie alarmu po określonej godzinie

Jeśli aplikacja wywołuje metodę set(), setInexactRepeating() lub setAndAllowWhileIdle(), alarm nigdy nie włącza się przed podanym czasem uruchomienia.

Na Androidzie 12 (poziom interfejsu API 31) i nowszych system wywołuje alarm w ciągu 1 godziny od podanego czasu aktywacji, chyba że obowiązują jakiekolwiek ograniczenia oszczędzania baterii, takie jak oszczędzanie baterii lub drzemka.

Dostarczanie alarmu w określonym przedziale czasu

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

Jeśli Twoja aplikacja jest kierowana na Androida w wersji 12 lub nowszej, system może opóźnić wywołanie alarmu o niedokładnym czasie o co najmniej 10 minut. Z tego powodu wartości parametru windowLengthMillis w polu 600000 są przycinane do 600000.

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

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

  1. Pierwszy alarm uruchamia się we wskazanym okresie.
  2. Kolejne alarmy uruchamiają się zwykle po upływie określonego czasu. Czas między dwoma kolejnymi wywołaniami alarmu może być różny.

Ustaw dokładny alarm

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

Większość aplikacji może planować zadania i wydarzenia za pomocą alarmów nieprecyzyjnych, aby realizować kilka typowych przypadków użycia. Jeśli główna funkcjonalność aplikacji zależy od alarmu o dokładnej godzinie (np. w przypadku budzika lub kalendarza), możesz ustawić alarm dokładny.

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

Poniższa lista zawiera typowe przepływy pracy, które mogą nie wymagać dokładnego alarmu:

Planowanie operacji związanych z czasem działania aplikacji
Klasa Handler zawiera kilka dobrych metod obsługi działań związanych z czasem, takich jak wykonywanie pracy co n sekund, gdy aplikacja jest aktywna: postAtTime() i postDelayed(). Pamiętaj, że te interfejsy API zależą od czasu działania systemu, a nie czasu rzeczywistego.
zaplanowane działania w tle, na przykład aktualizowanie aplikacji i przesyłanie logów.
WorkManager umożliwia zaplanowanie okresowej pracy zależnej od czasu. Możesz podać interwał powtarzania i flexInterval (minimum 15 minut), aby określić szczegółowy czas działania.
Określone przez użytkownika działanie, które powinno zostać wykonane po określonym czasie (nawet jeśli system jest nieaktywny)
Używaj alarmu nieprecyzyjnego. Wywołaj setAndAllowWhileIdle().
Określone przez użytkownika działanie, które powinno zostać wykonane po określonym czasie
Używaj alarmu nieprecyzyjnego. Wywołaj set().
Określone przez użytkownika działanie, które może zostać wykonane w określonym przedziale czasu.
Używaj alarmu nieprecyzyjnego. Wywołaj setWindow(). Pamiętaj, że w przypadku aplikacji na Androida 12 lub nowszego najkrótszy dozwolony okres to 10 minut.

Sposoby ustawiania dokładnego alarmu

Aplikacja może ustawiać alarmy precyzyjne, korzystając z jednej z tych metod. Metody te są uporządkowane w taki sposób, że metody znajdujące się bliżej końca listy obsługują więcej zadań o krytycznym znaczeniu, ale wymagają więcej zasobów systemowych.

setExact()

Wywołuj alarm o niemal ściśle określonej godzinie w przyszłości, o ile nie będą stosowane inne środki oszczędzania baterii.

Użyj tej metody, aby ustawiać alarmy precyzyjne, chyba że działanie aplikacji jest ważne dla użytkownika.

setExactAndAllowWhileIdle()

Wywołuj alarm o niemal dokładnie podanej godzinie w przyszłości, nawet jeśli będą obowiązywać środki mające na celu oszczędzanie baterii.

setAlarmClock()

Wywołuj alarm o konkretnej godzinie w przyszłości. Alarmy te są dobrze widoczne dla użytkowników, więc system nigdy nie dostosowuje godziny ich dostarczania. System identyfikuje te alarmy jako najbardziej krytyczne i w razie potrzeby pozostawia tryby niskiego zużycia energii do uruchomienia alarmów.

Wykorzystanie zasobów systemu

Gdy system uruchamia alarmy precyzyjne ustawione przez aplikację, urządzenie zużywa wiele zasobów, np. czas pracy na baterii, zwłaszcza w trybie oszczędzania energii. System nie może też łatwo grupować tych żądań, aby wydajniej wykorzystywać zasoby.

Zdecydowanie zalecamy, aby zawsze, gdy jest to możliwe, utworzyć niedokładny alarm. Aby wykonać dłuższą pracę, zaplanuj ją za pomocą funkcji WorkManager lub JobScheduler z alarmu BroadcastReceiver. Aby wykonać pracę, gdy urządzenie jest w trybie uśpienia, utwórz alarm niedokładny, używając opcji setAndAllowWhileIdle(), i uruchom zadanie z alarmu.

Deklarowanie odpowiednich uprawnień dotyczących dokładnego alarmu

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 poniżej:

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

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

USE_EXACT_ALARM

SCHEDULE_EXACT_ALARM

  • Udzielone przez użytkownika
  • Szerszy zestaw przypadków użycia
  • Aplikacje powinny potwierdzać, że te uprawnienia nie zostały unieważnione

Korzystanie z uprawnienia SCHEDULE_EXACT_ALARM

W przeciwieństwie do zasady USE_EXACT_ALARM uprawnienie SCHEDULE_EXACT_ALARM musi zostać przyznane przez użytkownika. Uprawnienia SCHEDULE_EXACT_ALARM mogą anulować zarówno użytkownik, jak i system.

Aby sprawdzić, czy aplikacja otrzymała to uprawnienie, wywołaj canScheduleExactAlarms(), zanim spróbujesz ustawić dokładny alarm. Gdy utracisz dla aplikacji uprawnienie SCHEDULE_EXACT_ALARM, aplikacja przestanie działać i zostaną anulowane wszystkie przyszłe alarmy precyzyjne. Oznacza to też, że wartość zwrócona przez canScheduleExactAlarms() pozostaje ważna przez cały cykl życia aplikacji.

Po przyznaniu aplikacji uprawnienia SCHEDULE_EXACT_ALARMS system wysyła ją do transmisji ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED. Aplikacja powinna zaimplementować odbiornik, który spełnia te wymagania:

  1. Potwierdza, że aplikacja nadal będzie miała dostęp specjalny. Aby to zrobić, wywołaj metodę canScheduleExactAlarms(). Ta weryfikacja chroni aplikację przed sytuacjami, w których użytkownik przyznał jej odpowiednie uprawnienia, a następnie anuluje je niemal natychmiast.
  2. Przekłada alarmy, których potrzebuje Twoja aplikacja na podstawie bieżącego stanu. Ta logika powinna być podobna do tej, którą robi aplikacja, gdy odbiera transmisję ACTION_BOOT_COMPLETED.

Poproś użytkowników o przyznanie uprawnienia SCHEDULE_EXACT_ALARM

Opcja nosi nazwę „Zezwalaj na ustawianie alarmów i przypomnień”
Rysunek 1. Specjalna strona dostępu do „Alarmów i przypomnień” w ustawieniach systemu, na której użytkownicy mogą zezwolić aplikacji na ustawianie dokładnych alarmów.

W razie potrzeby możesz przekierować użytkowników do ekranu Alarmy i przypomnienia w ustawieniach systemowych, jak pokazano na rysunku 1. Aby to zrobić:

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

Ustaw powtarzanie alarmu

Powtarzające się alarmy pozwalają systemowi powiadamiać aplikację o regularnym harmonogramie.

Źle zaprojektowany alarm może powodować rozładowywanie baterii i znacznie obciążać serwery. Dlatego w Androidzie 4.4 (poziom interfejsu API 19) i nowszych wszystkie powtarzające się alarmy są alarmami niedokładnymi.

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 aktywacji 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 jest uruchamiana po uruchomieniu alarmu. Gdy ustawisz drugi alarm, który korzysta z tej samej oczekującej intencji, zastąpi on oryginalny.

Aby anulować PendingIntent(), przekaż intencję FLAG_NO_CREATE do PendingIntent.getService(), co pozwoli uzyskać wystąpienie 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

Jedną z pierwszych kwestii, jakie należy wziąć pod uwagę przy powtarzaniu alarmu, jest jego typ.

Istnieją dwa ogólne typy zegara dla alarmów: „upływ czasu rzeczywistego” i „zegar w czasie rzeczywistym” (RTC). Upływ czasu w czasie rzeczywistym jest używany jako punkt odniesienia „czas od uruchomienia systemu”, a zegar w czasie rzeczywistym używa czasu UTC. Oznacza to, że czas rzeczywisty można ustawiać na podstawie upływu czasu (np. alarmu uruchamiającego się co 30 sekund), ponieważ nie ma na niego wpływu strefa czasowa ani region. Zegar w czasie rzeczywistym lepiej sprawdza się w przypadku alarmów, które są zależne od bieżącej lokalizacji.

Oba typy mają wersję „wybudzenie”, która oznacza wybudzanie procesora urządzenia, gdy ekran jest wyłączony. Dzięki temu alarm uruchomi się o zaplanowanej godzinie. Jest to przydatne, jeśli aplikacja jest zależna od czasu. np. gdy czas na wykonanie określonej operacji jest ograniczony. Jeśli nie korzystasz z trybu wybudzenia, wszystkie powtarzające się alarmy uruchomią się zaraz po wybudzeniu urządzenia.

Jeśli po prostu chcesz, aby alarm uruchamiał się o 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 chcesz, aby alarm uruchamiał się o określonej porze dnia, wybierz jeden z zegarów opartych na czasie rzeczywistym. Takie podejście ma jednak pewne wady. Aplikacja może nie być dobrze dostosowana do języka. Jeśli użytkownik zmieni ustawienia czasu na urządzeniu, może to spowodować nieoczekiwane działanie aplikacji. Używanie zegara w czasie rzeczywistym również nie skaluje się zbyt dobrze, jak opisano powyżej. Zalecamy, aby w miarę możliwości korzystać z alarmu „Upłynęło”.

Oto lista typów:

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

  • ELAPSED_REALTIME_WAKEUP: wywołuje urządzenie i uruchamia oczekującą intencję, gdy upłynie określony czas od uruchomienia urządzenia.

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

  • RTC_WAKEUP: aktywuje urządzenie w określonym czasie, aby uruchomić oczekującą intencję.

Przykłady upłyniętych alarmów w czasie rzeczywistym

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

Wybudź urządzenie, aby uruchomić alarm po 30 minutach i co 30 minut później:

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, aby uruchomić jednorazowy (jednorazowy) alarm 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 w czasie rzeczywistym

Oto kilka przykładów użycia narzędzia RTC_WAKEUP.

Wybudź urządzenie, aby uruchomić alarm o ok. 14:00, i powtórz 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);

Obudź urządzenie, aby uruchomić alarm 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);

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

Jak pisaliśmy wcześniej, wybór typu alarmu jest często pierwszym krokiem tworzenia alarmu. Kolejna różnica polega na tym, jak precyzyjne ma być alarmy. W przypadku większości aplikacji właściwym wyborem jest setInexactRepeating(). Jeśli korzystasz z tej metody, Android synchronizuje wiele powtarzających się alarmów, które nie są dokładne, i uruchamia je jednocześnie. Pozwala to zmniejszyć zużycie baterii.

W miarę możliwości unikaj używania alarmów precyzyjnych. W przypadku rzadko spotykanej aplikacji, która ma rygorystyczne wymagania czasowe, możesz ustawić dokładny alarm, wywołując metodę setRepeating().

Korzystając z funkcji setInexactRepeating(), nie możesz określić interwału niestandardowego tak, jak robisz to w przypadku setRepeating(). Musisz użyć jednej ze stałych przedziałów, np. INTERVAL_FIFTEEN_MINUTES, INTERVAL_DAY itd. Pełną listę znajdziesz AlarmManager.

Anuluj alarm

W zależności od aplikacji możesz mieć możliwość anulowania alarmu. Aby anulować alarm, wywołaj cancel() w Menedżerze alarmów, 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);
}

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 ponownie powtarzał alarm, gdy użytkownik zrestartuje urządzenie. Dzięki temu AlarmManager będzie kontynuować wykonywanie zadania 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 otrzymać komunikat ACTION_BOOT_COMPLETED, który jest przesyłany po zakończeniu uruchamiania 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. Zaimplementuj BroadcastReceiver, aby odbierać 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 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 rozruchu jest ustawiony na android:enabled="false". Oznacza to, że odbiornik nie zostanie wywołany, jeśli aplikacja go nie włączy. Zapobiega to niepotrzebnemu wywołaniu odbiornika rozruchowego. Możesz włączyć odbiornik (na przykład 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 tego odbiornika pozostanie on włączony nawet po ponownym uruchomieniu urządzenia. Inaczej mówiąc, automatyczne włączenie odbiorcy zastępuje ustawienie w pliku manifestu nawet po ponownym uruchomieniu. Odbiornik pozostanie włączony, dopóki aplikacja go nie wyłączy. Aby wyłączyć odbiornik (na przykład 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);
    

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śpienia, który pomaga wydłużyć czas pracy na baterii. Alarmy nie są uruchamiane, gdy urządzenie jest w trybie Tryb uśpienia Wszystkie zaplanowane alarmy są odkładane do momentu wyjścia przez urządzenie z trybu uśpienia. Jeśli musisz wykonać pracę nawet na urządzeniu nieaktywnym, masz do wyboru kilka opcji:

  • Ustaw dokładny alarm.

  • Użyj interfejsu WorkManager API, który służy do wykonywania pracy w tle. Możesz wskazać, że system ma przyśpieszyć pracę, aby jak najszybciej została zakończona. Więcej informacji znajdziesz w artykule o planowaniu zadań za pomocą WorkManagera.

Sprawdzone metody

Każdy wybór, jaki dokonasz podczas projektowania cyklicznego alarmu, może mieć wpływ na to, jak aplikacja wykorzystuje (lub nadużywa) zasoby systemowe. Weźmy np. popularną aplikację, która synchronizuje się z serwerem. Jeśli operacja synchronizacji odbywa się na podstawie godziny zegara, a każda instancja aplikacji jest synchronizowana o 23:00, obciążenie serwera może spowodować duże opóźnienia lub nawet „ataki typu DoS”. 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:

    • Wykonuj działania lokalne po uruchomieniu alarmu. „Praca lokalna” oznacza wszystko, co nie trafia na serwer ani nie wymaga danych z serwera.

    • Jednocześnie zaplanuj alarm zawierający żądania sieciowe, które mają się uruchamiać w losowym czasie.

  • Zmniejsz częstotliwość alarmu.

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

  • Nie ustawiaj godziny uruchamiania alarmu tak dokładnie, jak jest to konieczne.

    Użyj setInexactRepeating() zamiast setRepeating(). Gdy używasz setInexactRepeating(), Android synchronizuje powtarzające się alarmy z wielu aplikacji i uruchamia je jednocześnie. Dzięki temu zmniejsza się łączna liczba wybudzania urządzenia przez system, co zmniejsza wykorzystanie baterii. Od Androida 4.4 (poziom interfejsu API 19) wszystkie powtarzające się alarmy są alarmami niedokładnymi. Pamiętaj, że chociaż setInexactRepeating() jest lepszy od setRepeating(), nadal może przeciążyć serwer, jeśli każde wystąpienie aplikacji trafi na serwer w tym samym czasie. Dlatego w przypadku żądań sieciowych dodaj do alarmów trochę losowości, jak już wspomnieliśmy.

  • Jeśli to możliwe, nie stawiaj alarmu na godzinę.

    Powtarzające się alarmy, które zależą od konkretnego czasu wyzwalania, nie są dobrze skalowane. Jeśli możesz, użyj właściwości ELAPSED_REALTIME. Różne typy alarmów zostały szczegółowo opisane w następnej sekcji.