AlarmManager
) umożliwiają wykonywanie operacji opartych na czasie poza okresem aktywności aplikacji.
Możesz na przykład użyć alarmu do zainicjowania długotrwałej operacji, takiej jak uruchamianie usługi raz dziennie w celu pobrania prognozy pogody.
Alarmy mają te cechy:
Umożliwiają uruchamianie intencji o określonych porach lub w określonych odstępach czasu.
Możesz ich używać w połączeniu z odbiornikami transmisji, aby zaplanować zadania lub WorkRequests, aby wykonywać inne operacje.
Dział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, a samo urządzenie jest uśpione.
Pomagają zminimalizować wymagania dotyczące zasobów aplikacji. Możesz zaplanować operacje bez korzystania z zegarów ani usług działających w ciągu.
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.
Wysyłanie alarmu po określonej godzinie
Jeśli Twoja aplikacja wywołuje metodę set()
,
setInexactRepeating()
lub setAndAllowWhileIdle()
,
alarm nigdy nie włączy się przed określonym czasem.
W Androidzie 12 (poziom API 31) i nowszych system wywołuje alarm w ciągu 1 godziny od podanego czasu uruchomienia, chyba że obowiązują ograniczenia dotyczące oszczędzania baterii, takie jak Oszczędzanie baterii czy Doze.
Dostarcz alarm w wybranym przedziale czasu
Jeśli aplikacja wywoła metodę setWindow()
, alarm nigdy nie włączy się przed podanym czasem wywołania. O ile nie obowiązują żadne ograniczenia dotyczące oszczędzania baterii, alarm jest wysyłany w określonym przedziale czasowym, licząc od określonego czasu aktywacji.
Jeśli Twoja aplikacja jest kierowana na Androida 12 lub nowszego, system może opóźnić wywołanie nieprecyzyjnego alarmu z wyznaczonym przedziałem czasu o co najmniej 10 minut. Z tego powodu wartości parametrów windowLengthMillis
poniżej 600000
są przycinane do 600000
.
Uruchamiaj powtarzający się alarm w mniej więcej regularnych odstępach czasu
Jeśli Twoja aplikacja wywołuje funkcję setInexactRepeating()
, system wywołuje kilka alarmów:
- Pierwszy alarm włącza się w określonym oknie czasowym, licząc od podanego czasu uruchomienia.
- Kolejne alarmy zwykle włączają się po upływie określonego czasu. Czas między kolejnymi wywołaniami alarmu może się różnić.
Ustawianie precyzyjnego alarmu
System wywołuje dokładny alarm w konkretnym 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()
ipostDelayed()
. Pamiętaj, że te interfejsy API zależą od czasu działania systemu, a nie od czasu rzeczywistego. - zaplanowane działanie 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 iflexInterval
(co najmniej 15 minut), aby określić szczegółowy czas działania.- 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. W szczególności chodzi o numer
setAndAllowWhileIdle()
. - działanie określone przez użytkownika, które powinno nastąpić po określonym czasie;
- Użyj alarmu nieprecyzyjnego. W szczególności chodzi o numer
set()
. - Działanie określone przez użytkownika, które może zostać wykonane w określonym przedziale czasu
- Użyj alarmu nieprecyzyjnego. W szczególności chodzi o numer
setWindow()
. Jeśli aplikacja jest kierowana na Androida 12 lub nowszego, najniższa dopuszczalna długość okna to 10 minut.
Sposoby ustawiania precyzyjnego 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()
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ą bardzo widoczne dla użytkowników, system nigdy nie zmienia ich czasu dostawy. System rozpoznaje te alarmy jako najważniejsze i w razie potrzeby pozostawia tryby oszczędzania energii, aby je wyświetlić.
Wykorzystanie zasobów systemu
Gdy system uruchamia alarmy ustawione przez aplikację, urządzenie zużywa dużo zasobów, takich jak czas pracy na baterii, zwłaszcza jeśli jest w trybie oszczędzania energii. Ponadto system nie może łatwo grupować tych żądań, aby efektywniej wykorzystywać zasoby.
Zdecydowanie zalecamy 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 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 (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ą przyznawane w inny sposób i obsługują inne przypadki użycia. Aplikacja powinna używać precyzyjnych alarmów i zadeklarować uprawnienie SCHEDULE_EXACT_ALARM
lub USE_EXACT_ALARM
tylko wtedy, gdy funkcja widoczna dla użytkowników wymaga wykonywania działań w precyzyjnie określonym czasie.
USE_EXACT_ALARM
- Przyznano automatycznie
- nie może zostać cofnięty przez użytkownika.
- podlega nadchodzącym zasadom Google Play,
- Ograniczone przypadki użycia
SCHEDULE_EXACT_ALARM
- Udzielone przez użytkownika
- szerszy zakres zastosowań,
- Aplikacje powinny potwierdzać, że uprawnienia nie zostały cofnięte
Uprawnienie SCHEDULE_EXACT_ALARM
nie jest przyznawane wstępnie w przypadku świeżo zainstalowanych aplikacji kierowanych na Androida 13 (poziom API 33) lub nowszego. Jeśli użytkownik przeniesie dane aplikacji na urządzenie z Androidem 14, korzystając z kopii zapasowej i przywracania, na nowym urządzeniu zostanie odrzucone 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 ustawiony za pomocą obiektu OnAlarmListener
, np. za pomocą interfejsu API setExact
, uprawnienie SCHEDULE_EXACT_ALARM
nie jest wymagane.
Używanie uprawnienia SCHEDULE_EXACT_ALARM
W przeciwieństwie do zasady USE_EXACT_ALARM
uprawnienie SCHEDULE_EXACT_ALARM
musi być przyznane przez użytkownika. Użytkownik i system mogą cofnąć uprawnienia SCHEDULE_EXACT_ALARM
.
Aby sprawdzić, czy Twoja aplikacja ma to uprawnienie, przed użyciem alarmu precyzyjnego wywołaj funkcję canScheduleExactAlarms()
. Gdy uprawnienia SCHEDULE_EXACT_ALARM
zostaną cofnięte, aplikacja przestanie działać, a wszystkie przyszłe alarmy precyzyjne zostaną anulowane. Oznacza to też, że wartość zwracana przez funkcję canScheduleExactAlarms()
pozostaje prawidłowa przez cały cykl życia aplikacji.
Gdy aplikacja otrzyma uprawnienie SCHEDULE_EXACT_ALARMS
, system wyśle ją do transmisji ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED
. Aplikacja powinna implementować odbiornik wiadomości rozgłoszeniowych, który:
- potwierdza, że aplikacja nadal ma specjalne uprawnienia dostępu. Aby to zrobić, zadzwoń na numer
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. - 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_COMPLETED
transmisji.
Zapytaj użytkowników o przyznanie uprawnień SCHEDULE_EXACT_ALARM
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ć:
- W interfejsie aplikacji wyjaśnij użytkownikowi, dlaczego musi ona planować konkretne alarmy.
- Wywołaj intencję zawierającą działanie intencji
ACTION_REQUEST_SCHEDULE_EXACT_ALARM
.
Ustawianie alarmu powtarzającego się
Alarmy powtarzające się pozwalają systemowi wysyłać powiadomienia do aplikacji zgodnie z określonym harmonogramem.
Źle zaprojektowany alarm może rozładować baterię i znacznie obciążyć serwery. Z tego powodu na Androidzie 4.4 (poziom interfejsu API 19) i nowszych wszystkie alarmy powtarzające się są nieprecyzyjne.
Powtarzające się alarmy mają następujące cechy:
Typ alarmu. Więcej informacji znajdziesz w artykule Wybieranie typu alarmu.
Czas aktywacji. Jeśli podany przez Ciebie czas jest w przeszłości, alarm zostanie uruchomiony natychmiast.
Interwał alarmu. Na przykład raz dziennie, co godzinę lub co 5 minut.
Intencja oczekująca, która uruchamia się po aktywowaniu alarmu. Gdy ustawisz drugi alarm, który używa tego samego oczekującego zamiaru, zastąpi on pierwotny alarm.
Aby anulować PendingIntent()
, prześlij FLAG_NO_CREATE
do PendingIntent.getService()
, aby uzyskać instancję 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); }
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 ogólne typy zegara alarmowego: „upływający czas rzeczywisty” i „zegar czasu rzeczywistego” (RTC). Czas upływający w czasie rzeczywistym używa jako odniesienia „czasu od uruchomienia systemu”, a zegar czasu rzeczywistego używa czasu UTC (zegar ścienny). Oznacza to, że upływający czas rzeczywisty jest odpowiedni do ustawiania alarmu na podstawie upływu czasu (na przykład alarmu, który działa co 30 sekund), ponieważ nie jest on zależny od strefy czasowej ani lokalizacji. Zegar w czasie rzeczywistym lepiej sprawdza się w przypadku alarmów zależnych od regionu.
Oba typy mają wersję „budzenia”, która powoduje wybudzenie procesora urządzenia, jeśli ekran jest wyłączony. Dzięki temu alarm zostanie uruchomiony o zaplanowanej godzinie. Jest to przydatne, gdy aplikacja ma zależność czasową. Na przykład, jeśli ma ograniczony czas na wykonanie określonej operacji. Jeśli nie uż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 włączał się o określonej porze dnia, wybierz jeden z typów zegara opartego na czasie rzeczywistym. Pamiętaj jednak, że takie podejście może mieć pewne wady. Aplikacja może nie działać prawidłowo w innych lokalizacjach, a jeśli użytkownik zmieni ustawienia czasu na urządzeniu, może to spowodować nieoczekiwane działanie aplikacji. Jak już wspomnieliśmy, użycie typu alarmu zegarka w czasie rzeczywistym nie jest też zbyt elastyczne. 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ą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 ELAPSED_REALTIME_WAKEUP
Włącz urządzenie, aby włączyć alarm co 30 minut i co 30 minut po tym czasie:
Kotlin
// Hopefully your alarm will have a lower frequency than this! alarmMgr?.setInexactRepeating( AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR, AlarmManager.INTERVAL_HALF_HOUR, alarmIntent )
Java
// Hopefully your alarm will have a lower frequency than this! alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR, AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);
Aby uruchomić alarm jednorazowy (niepowtarzalny) w ciągu minuty:
Kotlin
private var alarmMgr: AlarmManager? = null private lateinit var alarmIntent: PendingIntent ... alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent -> PendingIntent.getBroadcast(context, 0, intent, 0) } alarmMgr?.set( AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 60 * 1000, alarmIntent )
Java
private AlarmManager alarmMgr; private PendingIntent alarmIntent; ... alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, AlarmReceiver.class); alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0); alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 60 * 1000, alarmIntent);
Przykłady alarmów zegara 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 nieprecyzyjnie powtarzanych alarmów i uruchamia je jednocześnie. Zmniejszy to zużycie baterii.
W miarę możliwości unikaj stosowania alarmów precyzyjnych. W przypadku rzadkich aplikacji, które mają rygorystyczne wymagania czasowe, możesz ustawić dokładny alarm, wywołując funkcję setRepeating()
.
W przypadku setInexactRepeating()
nie możesz określić niestandardowego przedziału czasowego w sposób dostępny 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 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 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ć:
W pliku manifestu aplikacji ustaw uprawnienie
RECEIVE_BOOT_COMPLETED
. Pozwala to aplikacji na odbieranieACTION_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"/>
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. } } }
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. 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 dokładny alarm.
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 o planowaniu zadań przy użyciu WorkManager.
Sprawdzone metody
Każdy wybór dokonany podczas projektowania alarmu powtarzającego 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ść (zakłócenia) do wszystkich żądań sieciowych, które są wywoływane w wyniku powtarzających się alarmów:
Po uruchomieniu alarmu możesz wykonywać dowolne czynności lokalne. „Praca lokalna” to wszystko, co nie wymaga korzystania z serwera ani przesyłania danych na serwer.
Jednocześnie zaplanuj alarm z żądaniami sieciowymi, które będą uruchamiane w losowym czasie.
Ogranicz częstotliwość alarmów do minimum.
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()
zamiastsetRepeating()
. Gdy używaszsetInexactRepeating()
, Android synchronizuje alarmy powtarzające się z kilku aplikacji i uruchamia je jednocześnie. Dzięki temu system musi uruchamiać urządzenie mniej razy, co zmniejsza zużycie baterii. Od Androida 4.4 (poziom interfejsu API 19) wszystkie alarmy powtarzające się są nieprecyzyjne. Pamiętaj, że chociażsetInexactRepeating()
jest lepszym rozwiązaniem niżsetRepeating()
, to nadal może przeciążyć serwer, jeśli każda instancja aplikacji łączy się z serwerem w przybliżeniu w tym samym czasie. Dlatego w przypadku żądań sieciowych dodaj do swoich alarmów pewną losowość, jak opisano wcześniej.Jeśli to możliwe, unikaj ustawiania alarmu na podstawie czasu zegara.
Alarmy powtarzające się, które są oparte na dokładnym czasie aktywacji, nie skalują się dobrze. Jeśli to możliwe, używaj formatu
ELAPSED_REALTIME
. Typy alarmów opisujemy bardziej szczegółowo w następnej sekcji.