AlarmManager
) ti consentono di eseguire operazioni basate sul tempo al di fuori del ciclo di vita della tua applicazione.
Ad esempio, puoi utilizzare un allarme per avviare un'operazione a lunga esecuzione, ad esempio avviare un servizio una volta al giorno per scaricare una previsione meteo.
Gli allarmi hanno le seguenti caratteristiche:
Consentono di attivare intent in orari e/o intervalli prestabiliti.
Puoi utilizzarli insieme ai ricevitori di trasmissione per pianificare job o WorkRequest per eseguire altre operazioni.
Operano al di fuori dell'applicazione, quindi puoi utilizzarli per attivare eventi o azioni anche quando l'app non è in esecuzione e anche se il dispositivo stesso è in modalità Sospensione.
Ti aiutano a ridurre al minimo i requisiti di risorse della tua app. Puoi pianificare le operazioni senza fare affidamento su timer o servizi in esecuzione continua.
Impostare una sveglia non esatta
Quando un'app imposta una sveglia imprecisa, il sistema la attiva in un momento futuro. Le sveglie imprecise forniscono alcune garanzie in merito alla tempistica di invio della sveglia, rispettando al contempo le limitazioni di risparmio della batteria, come Doze.
Gli sviluppatori possono sfruttare le seguenti garanzie API per personalizzare la tempistica di invio degli allarmi imprecisi.
Fornire una sveglia dopo un determinato periodo di tempo
Se la tua app chiama set()
,
setInexactRepeating()
,
o setAndAllowWhileIdle()
,
la sveglia non suona mai prima dell'ora di attivazione fornita.
Su Android 12 (livello API 31) e versioni successive, il sistema richiama la sveglia entro un'ora dall'ora di attivazione fornita, a meno che non siano in vigore limitazioni di risparmio energetico come il risparmio energetico o Doze.
Attivare una sveglia durante una finestra temporale
Se la tua app chiama setWindow()
, la sveglia non suona mai prima dell'ora di attivazione fornita. A meno che non siano in vigore restrizioni per il risparmio della batteria, l'allarme viene
attivato entro l'intervallo di tempo specificato, a partire dall'ora di attivazione
indicata.
Se la tua app ha come target Android 12 o versioni successive, il sistema può ritardare
l'invocazione di un allarme inexact con finestra temporale di almeno 10 minuti. Per
questo motivo, i valori del parametro windowLengthMillis
in 600000
vengono troncati a
600000
.
Inviare una sveglia ripetuta a intervalli più o meno regolari
Se la tua app chiama setInexactRepeating()
,
il sistema richiama più sveglie:
- Il primo allarme si attiva entro l'intervallo di tempo specificato, a partire dall'ora di attivazione indicata.
- Le sveglie successive in genere suonano dopo la scadenza della finestra temporale specificata. Il tempo che intercorre tra due invocazioni consecutive della sveglia può variare.
Impostare una sveglia esatta
Il sistema richiama un allarme esatto in un momento preciso del futuro.
La maggior parte delle app può pianificare attività ed eventi utilizzando allarmi imprecisi per completare diversi casi d'uso comuni. Se la funzionalità di base della tua app dipende da una sveglia temporizzata con precisione, ad esempio per un'app sveglia o un'app calendario, puoi utilizzare una sveglia esatta.
Casi d'uso che potrebbero non richiedere sveglie esatte
Il seguente elenco mostra i flussi di lavoro comuni che potrebbero non richiedere una sveglia esatta:
- Pianificazione delle operazioni di temporizzazione durante il ciclo di vita dell'app
- La classe
Handler
include diversi metodi validi per gestire le operazioni di temporizzazione, ad esempio eseguire alcune operazioni ogni n secondi, mentre l'app è attiva:postAtTime()
epostDelayed()
. Tieni presente che queste API si basano sull'uptime del sistema e non sul tempo reale. - Operazioni pianificate in background, ad esempio aggiornamento dell'app e caricamento dei log
WorkManager
fornisce un modo per pianificare un lavoro periodico sensibile al fattore temporale. Puoi fornire un intervallo di ripetizione eflexInterval
(minimo 15 minuti) per definire un runtime granulare per il lavoro.- Azione specificata dall'utente che deve essere eseguita dopo un periodo di tempo specifico (anche se il sistema è in stato di inattività)
- Utilizzare una sveglia non esatta. Nello specifico, chiama
setAndAllowWhileIdle()
. - Azione specificata dall'utente che deve verificarsi dopo un determinato periodo di tempo
- Utilizzare una sveglia non esatta. Nello specifico, chiama
set()
. - Azione specificata dall'utente che può verificarsi in un determinato arco temporale
- Utilizzare una sveglia non esatta. Nello specifico, chiama
setWindow()
. Tieni presente che, se la tua app ha come target Android 12 o versioni successive, la durata minima della finestra consentita è di 10 minuti.
Modi per impostare una sveglia esatta
La tua app può impostare sveglie esatte utilizzando uno dei seguenti metodi. Questi metodi sono ordinati in modo che quelli più vicini alla fine dell'elenco servano più attività sensibili al tempo, ma richiedono più risorse di sistema.
setExact()
Attiva una sveglia a un orario futuro quasi preciso, a condizione che non siano in vigore altre misure di risparmio energetico.
Utilizza questo metodo per impostare sveglie esatte, a meno che il lavoro dell'app non sia urgente per l'utente.
setExactAndAllowWhileIdle()
Attiva una sveglia in un momento futuro quasi preciso, anche se sono in vigore misure di risparmio energetico.
setAlarmClock()
Richiamare una sveglia a un'ora precisa nel futuro. Poiché questi avvisi sono molto visibili agli utenti, il sistema non ne modifica mai l'orario di invio. Il sistema identifica questi allarmi come i più critici e disattiva le modalità di risparmio energetico, se necessario, per inviare gli allarmi.
Consumo di risorse di sistema
Quando il sistema attiva allarmi esatti impostati dalla tua app, il dispositivo consuma molte risorse, come la batteria, soprattutto se è in modalità di risparmio energetico. Inoltre, il sistema non può raggruppare facilmente queste richieste per utilizzare le risorse in modo più efficiente.
Ti consigliamo vivamente di creare un allarme impreciso ogni volta che
è possibile. Per eseguire esercizi più lunghi, pianificali utilizzando
WorkManager
o
JobScheduler
dalla
BroadcastReceiver
della sveglia. Per eseguire il lavoro mentre
il dispositivo è in modalità Doze, crea una sveglia inesatta utilizzando
setAndAllowWhileIdle()
e avvia un job dalla sveglia.
Dichiarare l'autorizzazione Sveglia esatta appropriata
Se la tua app ha come target Android 12 o versioni successive, devi ottenere l'accesso speciale per le app "Sveglie e promemoria". A questo scopo, dichiara l'autorizzazione
SCHEDULE_EXACT_ALARM
nel file manifest dell'app, come mostrato nel seguente snippet di codice:
<manifest ...> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/> <application ...> ... </application> </manifest>
Se la tua app ha come target Android 13 (livello API 33) o versioni successive, hai la possibilità di
dichiarare l'autorizzazione SCHEDULE_EXACT_ALARM
o l'autorizzazione USE_EXACT_ALARM
.
<manifest ...> <uses-permission android:name="android.permission.USE_EXACT_ALARM"/> <application ...> ... </application> </manifest>
Anche se le autorizzazioni SCHEDULE_EXACT_ALARM
e USE_EXACT_ALARM
indicano le stesse funzionalità, vengono concesse in modo diverso e supportano casi d'uso
diversi. La tua app deve utilizzare le sveglie esatte e dichiarare l'autorizzazione SCHEDULE_EXACT_ALARM
o USE_EXACT_ALARM
solo se una funzione rivolta agli utenti nella tua app richiede azioni temporizzate in modo preciso.
USE_EXACT_ALARM
- Concesso automaticamente
- Non può essere revocato dall'utente
- Soggetto a un'imminente norma di Google Play
- Casi d'uso limitati
SCHEDULE_EXACT_ALARM
- Concessi dall'utente
- Un insieme più ampio di casi d'uso
- Le app devono confermare che l'autorizzazione non è stata revocata
L'autorizzazione SCHEDULE_EXACT_ALARM
non viene concessa in anticipo alle nuove installazioni di
app destinate ad Android 13 (livello API 33) e versioni successive. Se un utente trasferisce i dati
delle app a un dispositivo con Android 14 tramite un'operazione di backup e ripristino, l'autorizzazione
SCHEDULE_EXACT_ALARM
verrà negata sul nuovo dispositivo. Tuttavia, se
un'app esistente dispone già di questa autorizzazione, questa verrà pre-concessa quando
il dispositivo verrà aggiornato ad Android 14.
Nota: se la sveglia esatta è impostata utilizzando un
OnAlarmListener
oggetto, ad esempio con l'API
setExact
, l'autorizzazione SCHEDULE_EXACT_ALARM
non è necessaria.
Utilizzo dell'autorizzazione SCHEDULE_EXACT_ALARM
A differenza di USE_EXACT_ALARM
, l'autorizzazione SCHEDULE_EXACT_ALARM
deve essere
concessa dall'utente. Sia l'utente sia il sistema possono revocare l'autorizzazione
SCHEDULE_EXACT_ALARM
.
Per verificare se l'autorizzazione è concessa alla tua app, chiama
canScheduleExactAlarms()
prima di provare a impostare una sveglia esatta. Quando l'autorizzazione SCHEDULE_EXACT_ALARM
viene revocata per la tua app, l'app si arresta e tutte le sveglie esatte future
vengono annullate. Ciò significa anche che il valore restituito da
canScheduleExactAlarms()
rimane valido per l'intero ciclo di vita della tua app.
Quando l'autorizzazione SCHEDULE_EXACT_ALARMS
viene concessa alla tua app, il sistema le invia la trasmissione ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED
. La tua app deve implementare un ricevitore
di trasmissione che esegua le
seguenti operazioni:
- Conferma che la tua app dispone ancora dell'accesso speciale alle app. Per farlo, chiama
canScheduleExactAlarms()
. Questo controllo protegge la tua app dal caso in cui l'utente concede l'autorizzazione alla tua app, per poi revocarla quasi immediatamente dopo. - Ripianifica le sveglie esatte necessarie alla tua app in base al suo stato attuale.
Questa logica dovrebbe essere simile a quella della tua app quando riceve la trasmissione
ACTION_BOOT_COMPLETED
.
Chiedere agli utenti di concedere l'autorizzazione SCHEDULE_EXACT_ALARM
Se necessario, puoi indirizzare gli utenti alla schermata Sveglie e promemoria nelle impostazioni di sistema, come mostrato nella Figura 1. Per farlo, segui questi passaggi:
- Nell'interfaccia utente della tua app, spiega all'utente perché la tua app deve programmare sveglie esatte.
- Richiama un intent che includa l'azione
ACTION_REQUEST_SCHEDULE_EXACT_ALARM
dell'intent.
Impostare una sveglia ripetuta
Le sveglie ripetute consentono al sistema di inviare notifiche alla tua app in base a una pianificazione ricorrente.
Un allarme progettato male può causare il consumo della batteria e sovraccaricare i server. Per questo motivo, su Android 4.4 (livello API 19) e versioni successive, tutte le sveglie ripetute sono sveglie imprecise.
Una sveglia ripetuta ha le seguenti caratteristiche:
Un tipo di sveglia. Per ulteriori informazioni, consulta Scegliere un tipo di allarme.
Un orario di attivazione. Se l'ora del trigger specificata è nel passato, l'allarme si attiva immediatamente.
L'intervallo della sveglia. Ad esempio, una volta al giorno, ogni ora o ogni 5 minuti.
Un intent in attesa che viene attivato quando viene attivata la sveglia. Quando imposti una seconda sveglia che utilizza lo stesso intent in attesa, questa sostituisce la sveglia originale.
Per annullare un PendingIntent()
, passa
FLAG_NO_CREATE
a PendingIntent.getService()
per ottenere un'istanza dell'intent (se esiste), quindi passa l'intent a
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); }
Scegliere un tipo di sveglia
Una delle prime considerazioni da fare quando si utilizza una sveglia ripetuta è il tipo che deve avere.
Esistono due tipi generali di orologio per le sveglie: "tempo reale trascorso" e "orologio in tempo reale" (RTC). Il tempo reale trascorso utilizza come riferimento il "tempo trascorso dall'avvio del sistema", mentre l'orologio in tempo reale utilizza l'ora UTC (orologio a muro). Ciò significa che il tempo reale trascorso è adatto per impostare una sveglia in base al trascorrere del tempo (ad esempio, una sveglia che suona ogni 30 secondi), poiché non è influenzato dal fuso orario o dalle impostazioni internazionali. Il tipo di orologio in tempo reale è più adatto per le sveglie che dipendono dalle impostazioni internazionali correnti.
Entrambi i tipi hanno una versione "wakeup", che indica di riattivare la CPU del dispositivo se lo schermo è spento. In questo modo, la sveglia suonerà all'ora programmata. È utile se la tua app ha una dipendenza temporale. Ad esempio, se ha una finestra limitata per eseguire una determinata operazione. Se non utilizzi la versione di sveglia del tipo di sveglia, tutte le sveglie ripetute si attiveranno quando il dispositivo si riattiverà.
Se hai semplicemente bisogno che la sveglia suoni a un determinato intervallo (ad esempio, ogni mezz'ora), utilizza uno dei tipi di tempo reale trascorso. In generale, questa è la scelta migliore.
Se vuoi che la sveglia si attivi a una determinata ora del giorno, scegli uno dei tipi di orologio in tempo reale basati sull'orologio. Tieni presente, tuttavia, che questo approccio può presentare alcuni svantaggi. L'app potrebbe non essere tradotta correttamente in altre impostazioni internazionali e, se l'utente modifica l'impostazione dell'ora del dispositivo, potrebbe causare un comportamento imprevisto nell'app. Anche l'utilizzo di un tipo di sveglia con orologio in tempo reale non è scalabile, come descritto sopra. Ti consigliamo di utilizzare un allarme "tempo reale trascorso", se possibile.
Ecco l'elenco dei tipi:
ELAPSED_REALTIME
: Attiva l'intent in attesa in base al tempo trascorso dall'avvio del dispositivo, ma non lo riattiva. Il tempo trascorso include qualsiasi periodo di tempo durante il quale il dispositivo era in modalità Sospensione.ELAPSED_REALTIME_WAKEUP
: Riattiva il dispositivo e attiva l'intent in attesa dopo che è trascorso il periodo di tempo specificato dall'avvio del dispositivo.RTC
: Attiva l'intent in attesa all'ora specificata, ma non riattiva il dispositivo.RTC_WAKEUP
: riattiva il dispositivo per attivare l'intent in attesa all'ora specificata.
Esempi di sveglie in tempo reale trascorso
Ecco alcuni esempi di utilizzo di ELAPSED_REALTIME_WAKEUP
Riattiva il dispositivo per attivare la sveglia tra 30 minuti e ogni 30 minuti successivi:
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);
Attiva il dispositivo per impostare una sveglia una tantum (non ripetuta) tra un minuto:
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);
Esempi di sveglie dell'orologio in tempo reale
Ecco alcuni esempi di utilizzo di
RTC_WAKEUP
.
Riattiva il dispositivo per attivare la sveglia alle 14:00 circa e ripeti l'operazione una volta al giorno alla stessa ora:
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);
Riattiva il dispositivo per attivare la sveglia esattamente alle 8:30 e ogni 20 minuti successivi:
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);
Decidi il livello di precisione della sveglia
Come descritto in precedenza, la scelta del tipo di sveglia è spesso il primo passo per
creare una sveglia. Un'ulteriore distinzione riguarda la precisione della sveglia. Per la maggior parte delle app,
setInexactRepeating()
è la scelta giusta. Quando utilizzi questo metodo, Android sincronizza più sveglie ripetitive inesatte e le attiva
contemporaneamente. In questo modo si riduce il consumo della batteria.
Se possibile, evita di utilizzare le sveglie esatte. Tuttavia, per la rara app che ha requisiti di tempo rigidi, puoi impostare una sveglia esatta chiamando setRepeating()
.
Con setInexactRepeating()
,
non puoi specificare un intervallo personalizzato come puoi fare con
setRepeating()
.
Devi utilizzare una delle costanti di intervallo, ad esempio
INTERVAL_FIFTEEN_MINUTES
,
INTERVAL_DAY
e così via. Consulta AlarmManager
per l'elenco completo.
Annulla una sveglia
A seconda dell'app, potresti voler includere la possibilità di annullare la sveglia.
Per annullare una sveglia, chiama cancel()
in Alarm Manager, passando
PendingIntent
che non vuoi più
attivare. Ad esempio:
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); }
Avvia una sveglia al riavvio del dispositivo
Per impostazione predefinita, tutte le sveglie vengono annullate quando un dispositivo si spegne.
Per evitare che ciò accada, puoi progettare la tua applicazione
in modo che riavvii automaticamente una sveglia ripetuta se l'utente riavvia il dispositivo. In questo modo, il AlarmManager
continuerà a svolgere la sua attività senza che l'utente debba riavviare manualmente la sveglia.
Procedi nel seguente modo:
Imposta l'autorizzazione
RECEIVE_BOOT_COMPLETED
nel file manifest dell'applicazione. In questo modo, la tua app può ricevere l'intentACTION_BOOT_COMPLETED
trasmesso dopo il completamento dell'avvio del sistema (funziona solo se l'app è già stata avviata dall'utente almeno una volta):<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
Implementa un
BroadcastReceiver
per ricevere la trasmissione: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. } } }
Aggiungi il ricevitore al file manifest dell'app con un filtro per intent che filtra l'azione
ACTION_BOOT_COMPLETED
:<receiver android:name=".SampleBootReceiver" android:enabled="false"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"></action> </intent-filter> </receiver>
Tieni presente che nel manifest il ricevitore di avvio è impostato su
android:enabled="false"
. Ciò significa che il ricevitore non verrà chiamato a meno che l'applicazione non lo abiliti esplicitamente. Ciò impedisce la chiamata non necessaria del ricevitore di avvio. Puoi attivare un ricevitore (ad esempio, se l'utente imposta una sveglia) nel seguente modo: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);
Una volta attivato il ricevitore in questo modo, rimarrà attivo anche se l'utente riavvia il dispositivo. In altre parole, l'attivazione programmatica del ricevitore esegue l'override dell'impostazione del manifest, anche dopo i riavvii. Il ricevitore rimarrà attivo finché la tua app non lo disattiva. Puoi disattivare un destinatario (ad esempio, se l'utente annulla una sveglia) nel seguente modo:
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);
Richiamare le sveglie mentre il dispositivo è in modalità Doze
I dispositivi con Android 6.0 (livello API 23) supportano la modalità Doze, che contribuisce a prolungare la durata della batteria del dispositivo. Le sveglie non vengono attivate quando il dispositivo è in modalità Doze. Tutte le sveglie programmate vengono posticipate fino a quando il dispositivo non esce dalla modalità Doze. Se devi completare il lavoro anche quando il dispositivo è inattivo, sono disponibili diverse opzioni:
Imposta una sveglia esatta.
Utilizza l'API WorkManager, creata per eseguire il lavoro in background. Puoi indicare al sistema di accelerare il tuo lavoro in modo che venga completato il prima possibile. Per saperne di più, vedi Pianificare le attività con WorkManager
Best practice
Ogni scelta che fai nella progettazione della sveglia ripetuta può avere conseguenze sul modo in cui la tua app utilizza (o abusa) delle risorse di sistema. Ad esempio, immagina un'app molto usata che si sincronizza con un server. Se l'operazione di sincronizzazione si basa sull'ora e ogni istanza dell'app si sincronizza alle 23:00, il carico sul server potrebbe causare una latenza elevata o persino un "rifiuto del servizio". Segui queste best practice per l'utilizzo delle sveglie:
Aggiungi casualità (jitter) a qualsiasi richiesta di rete che viene attivata in seguito a un allarme ripetuto:
Eseguire qualsiasi lavoro locale quando viene attivato l'allarme. Per "lavoro locale" si intende qualsiasi operazione che non raggiunge un server o non richiede i dati del server.
Allo stesso tempo, pianifica l'attivazione dell'allarme che contiene le richieste di rete in un periodo di tempo casuale.
Riduci al minimo la frequenza degli allarmi.
Non riattivare inutilmente il dispositivo (questo comportamento è determinato dal tipo di sveglia, come descritto in Scegliere un tipo di sveglia).
Non impostare l'ora di attivazione della sveglia con una precisione superiore a quella necessaria.
Utilizza
setInexactRepeating()
invece disetRepeating()
. Quando utilizzisetInexactRepeating()
, Android sincronizza le sveglie ripetute di più app e le attiva contemporaneamente. In questo modo si riduce il numero totale di volte in cui il sistema deve riattivare il dispositivo, riducendo così il consumo della batteria. A partire da Android 4.4 (livello API 19), tutte le sveglie ripetitive sono sveglie imprecise. Tieni presente che, sebbenesetInexactRepeating()
rappresenti un miglioramento rispetto asetRepeating()
, può comunque sovraccaricare un server se ogni istanza di un'app lo raggiunge all'incirca nello stesso momento. Pertanto, per le richieste di rete, aggiungi un po' di casualità alle sveglie, come discusso in precedenza.Se possibile, evita di basare la sveglia sull'ora.
Le sveglie ripetute basate su un orario di attivazione preciso non sono scalabili. Se possibile, utilizza
ELAPSED_REALTIME
. I diversi tipi di sveglia sono descritti in modo più dettagliato nella sezione seguente.