Planowanie alarmów

Alarmy (oparte na klasie AlarmManager) umożliwiają wykonywanie operacji opartych na czasie poza czasem działania aplikacji. Możesz na przykład użyć alarmu, aby zainicjować długo trwającą operację, taką jak uruchamianie usługi raz dziennie w celu pobrania prognozy pogody.

Alarmy mają te cechy:

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

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

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

  • Pomagają zminimalizować wymagania aplikacji dotyczące zasobów. Możesz planować operacje bez konieczności korzystania z liczników czasu lub ciągłego działania usług.

Ustawianie alarmu niedokładnego

Gdy aplikacja ustawia alarm niedokładny, system dostarcza go w określonym momencie w przyszłości. Alarmy niedokładne dają pewne gwarancje dotyczące czasu dostarczenia alarmu, ale uwzględniają ograniczenia związane z oszczędzaniem baterii, takie jak Doze.

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

Włączanie alarmu po określonym czasie

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

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

Włączanie alarmu w określonym przedziale czasu

Jeśli aplikacja wywołuje metodę setWindow(), alarm nigdy nie włączy się przed podanym czasem aktywacji. Jeśli nie obowiązują żadne ograniczenia związane z oszczędzaniem baterii, alarm jest dostarczany w określonym przedziale czasu, zaczynając od podanego czasu aktywacji.

Jeśli aplikacja jest kierowana na Androida 12 lub nowszego, system może opóźnić wywołanie niedokładnego alarmu z oknem czasowym o co najmniej 10 minut. Z tego powodu wartości parametru windowLengthMillis poniżej 600000 są zwykle przycinane do 600000. System może obsługiwać mniejsze okna, zwłaszcza jeśli alarm ma zostać wywołany w najbliższej przyszłości.

Wysyłanie powtarzającego się alarmu w mniej więcej regularnych odstępach czasu.

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

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

Ustawianie alarmu precyzyjnego

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

Większość aplikacji może planować zadania i wydarzenia za pomocą alarmów niedokładnych, aby realizować kilka typowych przypadków użycia. Jeśli główna funkcjonalność aplikacji zależy od alarmu o precyzyjnym czasie – np. w przypadku 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 przepływów pracy, które mogą nie wymagać alarmu precyzyjnego:

Planowanie operacji związanych z czasem podczas cyklu życia aplikacji
Klasa Handler zawiera kilka dobrych metod obsługi operacji związanych z czasem, takich jak wykonywanie określonych zadań co n sekund, gdy aplikacja jest aktywna: postAtTime() i postDelayed(). Pamiętaj, że te interfejsy API korzystają z czasu działania systemu, a nie z czasu rzeczywistego.
zaplanowane zadania w tle, takie jak aktualizowanie aplikacji i przesyłanie dzienników;
WorkManager umożliwia planowanie okresowych zadań, które muszą być wykonywane w określonym czasie. Możesz podać interwał powtarzania i flexInterval (co najmniej 15 minut), aby określić szczegółowy czas działania zadania.
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. Wywołaj funkcję setAndAllowWhileIdle().
Działanie określone przez użytkownika, które powinno nastąpić po określonym czasie
Użyj alarmu nieprecyzyjnego. Wywołaj funkcję set().
Działanie określone przez użytkownika, które może wystąpić w określonym przedziale czasu.
Użyj alarmu nieprecyzyjnego. Wywołaj funkcję setWindow(). Pamiętaj, że jeśli aplikacja jest kierowana na Androida 12 lub nowszego, najkrótszy dozwolony czas trwania okna to 10 minut.

Sposoby ustawiania alarmu precyzyjnego

Aplikacja może ustawiać alarmy precyzyjne za pomocą jednej z tych metod. Metody te są uporządkowane w taki sposób, że te znajdujące się bliżej dołu listy obsługują zadania bardziej krytyczne czasowo, ale wymagają więcej zasobów systemowych.

setExact()

Wywołaj alarm w przyszłości o prawie dokładnej godzinie, o ile nie obowiązują inne środki oszczędzania baterii.

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

setExactAndAllowWhileIdle()

Wywołaj alarm w określonym czasie w przyszłości, nawet jeśli obowiązują środki oszczędzania baterii.

setAlarmClock()

Wywołaj alarm o określonej godzinie w przyszłości. Te alarmy są dobrze widoczne dla użytkowników, dlatego system nigdy nie dostosowuje czasu ich dostarczenia. System identyfikuje te alarmy jako najbardziej krytyczne i w razie potrzeby wyłącza tryby oszczędzania baterii, aby je dostarczyć.

Wykorzystanie zasobów systemowych

Gdy system uruchamia alarmy precyzyjne ustawione przez aplikację, urządzenie zużywa dużo zasobów, np. baterii, zwłaszcza gdy 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ć alarmy niedokładne. 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ą metody setAndAllowWhileIdle() i uruchom zadanie z alarmu.

Zadeklaruj odpowiednie uprawnienia dostępu do alarmów precyzyjnych

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

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

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

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

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

USE_EXACT_ALARM

SCHEDULE_EXACT_ALARM

  • Przyznane przez użytkownika
  • Szerszy zakres przypadków użycia
  • Aplikacje powinny potwierdzić, że uprawnienia nie zostały cofnięte

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

Uwaga: jeśli alarm precyzyjny jest ustawiony za pomocą obiektu OnAlarmListener, np. 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. Uprawnienie SCHEDULE_EXACT_ALARM może zostać cofnięte zarówno przez użytkownika, jak i system.

Aby sprawdzić, czy aplikacja ma przyznane uprawnienie, przed próbą ustawienia alarmu precyzyjnego wywołaj canScheduleExactAlarms(). Gdy uprawnienie SCHEDULE_EXACT_ALARM zostanie odebrane aplikacji, aplikacja zostanie zatrzymana, a wszystkie przyszłe alarmy precyzyjne zostaną anulowane. Oznacza to również, że wartość zwracana przez canScheduleExactAlarms() pozostaje ważna przez cały cykl życia aplikacji.

Gdy aplikacja otrzyma uprawnienie SCHEDULE_EXACT_ALARMS, system wysyła do niej komunikat ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED. Aplikacja powinna wdrożyć odbiornik komunikatów, który:

  1. potwierdza, że aplikacja nadal ma specjalny dostęp. Aby to zrobić, zadzwoń pod numer canScheduleExactAlarms(). Ta kontrola chroni aplikację przed sytuacją, w której użytkownik przyznaje jej uprawnienia, a następnie niemal natychmiast je cofa.
  2. ponownie zaplanować wszystkie alarmy precyzyjne, których potrzebuje aplikacja, na podstawie jej bieżącego stanu; Ta logika powinna być podobna do tej, którą aplikacja stosuje po otrzymaniu komunikatu ACTION_BOOT_COMPLETED.

Poproś użytkowników o przyznanie uprawnienia SCHEDULE_EXACT_ALARM

Ta opcja nosi nazwę „Zezwalaj na ustawianie alarmów i przypomnień”.
Rysunek 1. „Alarmy i przypomnienia” w ustawieniach systemu, gdzie użytkownicy mogą zezwolić 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 rysunku 1. Aby to zrobić, wykonaj następujące czynności:

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

Ustawianie alarmu powtarzalnego

Alarmy powtarzające się umożliwiają systemowi powiadamianie aplikacji według cyklicznego harmonogramu.

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

Alarm powtarzający się ma te cechy:

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

  • czas aktywacji, Jeśli podany czas aktywacji należy do przeszłości, alarm włączy się natychmiast.

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

  • Intencja oczekująca, która jest uruchamiana po wywołaniu alarmu. Gdy ustawisz drugi alarm, który używa tej samej intencji oczekującej, zastąpi on pierwotny alarm.

Aby anulować PendingIntent(), przekaż FLAG_NO_CREATE do PendingIntent.getService(), aby uzyskać instancję intencji (jeśli istnieje), a następnie przekaż tę intencję do AlarmManager.cancel().

Kotlin

val alarmManager =
    context.getSystemService(Context.ALARM_SERVICE) as? AlarmManager
val pendingIntent =
    PendingIntent.getService(context, requestId, intent,
                                PendingIntent.FLAG_NO_CREATE)
if (pendingIntent != null && alarmManager != null) {
  alarmManager.cancel(pendingIntent)
}

Java

AlarmManager alarmManager =
    (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent =
    PendingIntent.getService(context, requestId, intent,
                                PendingIntent.FLAG_NO_CREATE);
if (pendingIntent != null && alarmManager != null) {
  alarmManager.cancel(pendingIntent);
}

Wybieranie typu alarmu

Jedną z pierwszych kwestii, które należy rozważyć podczas korzystania z alarmu powtarzalnego, jest jego typ.

Istnieją 2 główne typy zegarów alarmów: „czas rzeczywisty, który upłynął” i „zegar czasu rzeczywistego” (RTC). Czas rzeczywisty, który upłynął, używa jako odniesienia „czasu od uruchomienia systemu”, a zegar czasu rzeczywistego używa czasu UTC (zegara ściennego). Oznacza to, że rzeczywisty czas, który upłynął, jest odpowiedni do ustawiania alarmu na podstawie upływu czasu (np. alarmu, który uruchamia się co 30 sekund), ponieważ nie ma na niego wpływu strefa czasowa ani lokalizacja. Typ zegara czasu rzeczywistego lepiej nadaje się do alarmów, które zależą od bieżących ustawień regionalnych.

Oba typy mają wersję „wybudzania”, która powoduje wybudzenie 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. na przykład jeśli ma ograniczony czas na wykonanie określonej operacji. Jeśli nie użyjesz wersji alarmu, która wybudza urządzenie, 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 typów czasu rzeczywistego. Ogólnie rzecz biorąc, jest to lepszy wybór.

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

Oto lista typów:

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

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

  • RTC: uruchamia intencję oczekującą o określonej godzinie, ale nie wybudza urządzenia.

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

Przykłady alarmów czasu rzeczywistego, który upłynął

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

Wybudź urządzenie, aby uruchomić alarm za 30 minut i 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, aby uruchomić jednorazowy (niepowtarzający się) 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 zegara czasu rzeczywistego

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

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

Wybudzaj urządzenie, aby uruchomić alarm dokładnie o 8:30 i 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 wspomniano wcześniej, wybór typu alarmu jest często pierwszym krokiem podczas tworzenia alarmu. Kolejną kwestią jest to, jak precyzyjny ma być alarm. W przypadku większości aplikacji najlepszym wyborem jest setInexactRepeating(). Gdy używasz tej metody, Android synchronizuje wiele niedokładnych powtarzających się alarmów i uruchamia je jednocześnie. Zmniejsza to zużycie baterii.

W miarę możliwości unikaj używania alarmów precyzyjnych. Jeśli jednak aplikacja ma rygorystyczne wymagania czasowe, możesz ustawić alarm precyzyjny, wywołując setRepeating().

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

Anulowanie alarmu

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

Uruchamianie alarmu po ponownym uruchomieniu urządzenia

Domyślnie wszystkie alarmy są anulowane, gdy urządzenie się wyłącza. Aby temu zapobiec, możesz zaprojektować aplikację tak, aby automatycznie uruchamiała ponownie 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 ponownego uruchamiania alarmu przez użytkownika.

Aby to zrobić:

  1. Ustaw uprawnienie RECEIVE_BOOT_COMPLETED w pliku manifestu aplikacji. Dzięki temu aplikacja może odbierać ACTION_BOOT_COMPLETED, które jest transmitowane po zakończeniu uruchamiania systemu (działa to tylko wtedy, gdy użytkownik uruchomił już aplikację co najmniej raz):

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

    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 z filtrem intencji, który filtruje działanie ACTION_BOOT_COMPLETED:

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

    Zwróć uwagę, że w pliku manifestu odbiornik rozruchu jest ustawiony na android:enabled="false". Oznacza to, że odbiornik nie zostanie wywołany, chyba że aplikacja wyraźnie go włączy. Zapobiega to niepotrzebnemu wywoływaniu odbiornika rozruchu. Możesz włączyć odbiornik (np. gdy użytkownik ustawia 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 odbiornik w ten sposób, pozostanie on włączony, nawet jeśli użytkownik ponownie uruchomi urządzenie. Innymi słowy, automatyczne włączenie odbiornika zastępuje ustawienie manifestu, nawet po ponownym uruchomieniu. Odbiornik pozostanie włączony, dopóki nie wyłączy go aplikacja. Odbiornik możesz wyłączyć (np. gdy użytkownik anuluje alarm) w ten sposób:

    Kotlin

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

    Java

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

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

Urządzenia z Androidem 6.0 (interfejs API na poziomie 23) obsługują tryb Doze, 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ą odraczane do momentu wyjścia urządzenia z trybu uśpienia. Jeśli musisz wykonać pracę, nawet gdy urządzenie jest bezczynne, masz do wyboru kilka opcji:

  • ustawić alarm precyzyjny,

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

Sprawdzone metody

Każda decyzja, którą podejmujesz podczas projektowania powtarzającego się alarmu, może mieć konsekwencje dla sposobu, w jaki aplikacja korzysta z zasobów systemowych (lub je nadużywa). Wyobraź sobie na przykład popularną aplikację, która synchronizuje się z serwerem. Jeśli operacja synchronizacji jest oparta na czasie zegarowym i każda instancja aplikacji synchronizuje się o 23:00, obciążenie serwera może spowodować duże opóźnienie, a nawet „atak typu DoS”. Postępuj zgodnie z tymi sprawdzonymi metodami korzystania z alarmów:

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

    • wykonywać żadnych działań lokalnych po uruchomieniu alarmu. „Praca lokalna” oznacza wszystko, co nie wymaga połączenia z serwerem ani danych z serwera.

    • Jednocześnie zaplanuj alarm zawierający żądania sieciowe, który ma się uruchomić w losowym momencie.

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

  • nie wybudzać niepotrzebnie urządzenia (to zachowanie jest określane przez typ alarmu, jak opisano w sekcji Wybieranie typu alarmu).

  • Nie ustawiaj czasu aktywacji alarmu bardziej precyzyjnie, niż 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. Zmniejsza to łączną liczbę wybudzeń urządzenia przez system, a tym samym zużycie baterii. Od Androida 4.4 (poziom interfejsu API 19) wszystkie alarmy powtarzające się są alarmami niedokładnymi. Pamiętaj, że chociaż setInexactRepeating() jest ulepszeniem w stosunku do setRepeating(), nadal może przeciążyć serwer, jeśli wszystkie instancje aplikacji będą się z nim łączyć mniej więcej w tym samym czasie. Dlatego w przypadku żądań sieciowych dodaj do alarmów pewną losowość, jak opisano wcześniej.

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

    Powtarzające się alarmy, które są oparte na dokładnym czasie aktywacji, nie skalują się dobrze. Jeśli możesz, użyj ELAPSED_REALTIME. Różne typy alarmów zostały szczegółowo opisane w następnej sekcji.