Programmare sveglie

Gli allarmi (basati sulla classe AlarmManager) consentono di eseguire operazioni basate sul tempo al di fuori della durata della tua applicazione. Ad esempio, potresti utilizzare una sveglia per avviare un'operazione a lunga esecuzione, come avviare un servizio una volta al giorno per scaricare una previsione meteo.

Gli allarmi hanno le seguenti caratteristiche:

  • Ti permettono di attivare gli intent a orari e/o intervalli prestabiliti.

  • Puoi utilizzarle in combinazione con i broadcast receiver per pianificare job o WorkRequests per eseguire altre operazioni.

  • Questi funzionano 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 sospensione.

  • Ti aiutano a ridurre al minimo i requisiti di risorse della tua app. Puoi pianificare le operazioni senza dover fare affidamento su timer o servizi in esecuzione continua.

Impostare una sveglia inesatta

Quando un'app imposta una allarme inesatta, il sistema invia l'allarme in un determinato momento in futuro. Gli allarmi inesatti forniscono alcune garanzie sulla tempistica di invio degli allarmi, rispettando al contempo le limitazioni relative al risparmio della batteria, come la funzionalità Sospensione.

Gli sviluppatori possono sfruttare le garanzie dell'API riportate di seguito per personalizzare la tempistica della consegna di allarmi inesatti.

Inviare una sveglia dopo un orario specifico

Se l'app chiama set(), setInexactRepeating() o setAndAllowWhileIdle(), la sveglia non si attiva mai prima dell'orario di attivazione specificato.

Su Android 12 (livello API 31) e versioni successive, il sistema attiva la sveglia entro un'ora dall'orario di attivazione specificato, a meno che non siano in vigore restrizioni per il risparmio energetico, ad esempio Risparmio batteria o Sospensione.

Inviare una sveglia in un intervallo di tempo

Se la tua app chiama setWindow(), la sveglia non si attiva mai prima del tempo di attivazione specificato. A meno che non siano in vigore restrizioni per il risparmio della batteria, l'allarme viene inviato entro l'intervallo di tempo specificato, a partire dall'ora di attivazione specificata.

Se la tua app ha come target Android 12 o versioni successive, il sistema può ritardare la chiamata di una sveglia inesatta con intervallo temporale di almeno 10 minuti. Per questo motivo, i valori del parametro windowLengthMillis in 600000 sono troncati a 600000.

Inviare una sveglia ricorrente a intervalli circa regolari

Se l'app chiama setInexactRepeating(), il sistema attiva più sveglie:

  1. La prima sveglia suona nell'intervallo di tempo specificato, a partire dall'ora di attivazione specificata.
  2. Le sveglie successive solitamente suonano dopo che è trascorso l'intervallo di tempo specificato. Il tempo tra due chiamate consecutive della sveglia può variare.

Impostare una sveglia esatta

Il sistema attiva una sveglia esatta in un momento preciso nel futuro.

La maggior parte delle app può programmare attività ed eventi utilizzando sveglie inesatte per completare diversi casi d'uso comuni. Se la funzionalità di base dell'app dipende da una sveglia a tempo preciso, ad esempio un'app sveglia o un'app di calendario, puoi usare una sveglia esatta.

Casi d'uso che potrebbero non richiedere sveglie esatte

Il seguente elenco mostra flussi di lavoro comuni che potrebbero non richiedere un allarme esatto:

Pianificare le operazioni di sincronizzazione per l'intero ciclo di vita dell'app
La classe Handler include diversi metodi validi per gestire le operazioni di sincronizzazione, ad esempio eseguire alcune operazioni ogni n secondi mentre l'app è attiva: postAtTime() e postDelayed(). Tieni presente che queste API si basano sull'uptime del sistema e non sul tempo reale.
Operazioni in background pianificate, ad esempio l'aggiornamento dell'app e il caricamento dei log
WorkManager consente di pianificare il lavoro periodico sensibile al tempo. Puoi fornire un intervallo di ripetizione e flexInterval (minimo 15 minuti) per definire un runtime granulare per il lavoro.
Azione specificata dall'utente che dovrebbe verificarsi dopo un determinato periodo di tempo (anche se il sistema è in stato di inattività)
Usa una sveglia inesatta. In particolare, chiama setAndAllowWhileIdle().
Azione specificata dall'utente che deve avvenire dopo un intervallo di tempo specifico
Usa una sveglia inesatta. In particolare, chiama set().
Azione specificata dall'utente che può verificarsi entro un periodo di tempo specificato
Usa una sveglia inesatta. In particolare, chiama setWindow(). Tieni presente che, se la tua app ha come target Android 12 o versioni successive, la finestra minima consentita sarà di 10 minuti.

Come impostare una sveglia esatta

La tua app può impostare sveglie esatte utilizzando uno dei seguenti metodi. Questi metodi sono ordinati in modo tale che quelli più vicini alla fine dell'elenco svolgano attività più critiche in termini di tempo, ma richiedono più risorse di sistema.

setExact()

Attiva una sveglia in un momento futuro quasi preciso, a condizione che non siano state applicate altre misure di risparmio della batteria.

Utilizza questo metodo per impostare sveglie esatte, a meno che il lavoro dell'app non sia critico per l'utente.

setExactAndAllowWhileIdle()

Consente di attivare una sveglia a un'ora quasi precisa nel futuro, anche se sono state applicate misure per risparmiare batteria.

setAlarmClock()

Consente di attivare una sveglia a un'ora precisa nel futuro. Poiché questi allarmi sono altamente visibili agli utenti, il sistema non regola mai i loro tempi di consegna. Il sistema identifica questi allarmi come i più critici e lascia le modalità a basso consumo, se necessario, per inviare gli allarmi.

Consumo di risorse di sistema

Quando il sistema attiva esattamente gli allarmi impostati dall'app, il dispositivo utilizza una grande quantità di risorse, ad esempio la durata della batteria, soprattutto se è in modalità di risparmio energetico. Inoltre, il sistema non può facilmente eseguire il batch di queste richieste per usare le risorse in modo più efficiente.

Ti consigliamo vivamente di creare una sveglia inesatta quando possibile. Per lavorare più a lungo, programmalo utilizzando WorkManager o JobScheduler dal dispositivo BroadcastReceiver della sveglia. Per eseguire il lavoro mentre il dispositivo è in modalità Sospensione, crea una sveglia inesatta utilizzando setAndAllowWhileIdle() e avvia un job dalla sveglia.

Dichiara l'autorizzazione Sveglia esatta appropriata

Se la tua app è destinata ad Android 12 o versioni successive, devi ottenere l'accesso speciale all'app "Sveglie e promemoria". Per farlo, dichiara l'autorizzazione SCHEDULE_EXACT_ALARM nel file manifest della tua app, come mostrato nello snippet di codice seguente:

<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, puoi dichiarare l'autorizzazione SCHEDULE_EXACT_ALARM o USE_EXACT_ALARM.

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

Sebbene entrambe le autorizzazioni SCHEDULE_EXACT_ALARM e USE_EXACT_ALARM indichino le stesse funzionalità, vengono concesse in modo diverso e supportano casi d'uso diversi. L'app deve usare sveglie esatte e dichiarare l'autorizzazione SCHEDULE_EXACT_ALARM o USE_EXACT_ALARM, solo se una funzione rivolta all'utente nell'app richiede azioni temporizzate in modo preciso.

USE_EXACT_ALARM

SCHEDULE_EXACT_ALARM

  • Concesso dall'utente
  • Set più ampio di casi d'uso
  • Le app devono confermare che l'autorizzazione non è stata revocata

L'autorizzazione SCHEDULE_EXACT_ALARM non è stata pre-concessa alle nuove installazioni di app che hanno come target Android 13 (livello API 33) e versioni successive. Se un utente trasferisce i dati dell'app a un dispositivo con Android 14 tramite un'operazione di backup e ripristino, l'autorizzazione SCHEDULE_EXACT_ALARM viene negata sul nuovo dispositivo. Tuttavia, se un'app esistente dispone già di questa autorizzazione, verrà concessa in anticipo quando il dispositivo eseguirà l'upgrade ad Android 14.

Nota: se la sveglia esatta viene impostata utilizzando un oggetto OnAlarmListener, ad esempio con l'API setExact, non è necessaria l'autorizzazione SCHEDULE_EXACT_ALARM.

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 che il sistema possono revocare l'autorizzazione SCHEDULE_EXACT_ALARM.

Per verificare se l'autorizzazione è stata concessa alla tua app, chiama canScheduleExactAlarms() prima di provare a impostare una sveglia esatta. Quando viene revocata l'autorizzazione SCHEDULE_EXACT_ALARM per la tua app, l'app viene interrotta 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 dell'app.

Quando alla tua app viene concessa l'autorizzazione SCHEDULE_EXACT_ALARMS, il sistema le invia la trasmissione di ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED. La tua app deve implementare un ricevitore di trasmissione che:

  1. Verifica che la tua app abbia ancora accesso speciale per le app. Per farlo, chiama il numero canScheduleExactAlarms(). Questo controllo protegge l'app dal caso in cui l'utente conceda all'app l'autorizzazione, poi la revoca quasi immediatamente dopo.
  2. Riprogramma tutte le sveglie esatte di cui la tua app ha bisogno, in base al suo stato attuale. Questa logica dovrebbe essere simile a quella dell'app quando riceve la trasmissione di ACTION_BOOT_COMPLETED.

Chiedi agli utenti di concedere l'autorizzazione SCHEDULE_EXACT_ALARM

L&#39;opzione è &quot;Consenti impostazione di sveglie e promemoria&quot;
Figura 1. Pagina speciale di accesso alle app "Sveglie e promemoria " nelle impostazioni di sistema, in cui gli utenti possono consentire all'app di impostare sveglie esatte.

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:

  1. Nell'interfaccia utente dell'app, spiega all'utente perché l'app deve programmare sveglie esatte.
  2. Richiama un intent che include l'azione di intent ACTION_REQUEST_SCHEDULE_EXACT_ALARM.

Impostare una sveglia ricorrente

La ripetizione delle sveglie consente al sistema di inviare una notifica all'app in base a una programmazione ripetibile.

Un allarme progettato male può causare un consumo eccessivo della batteria e un carico significativo sui server. Per questo motivo, su Android 4.4 (livello API 19) e versioni successive, tutti gli allarmi ripetuti sono allarmi inesatti.

Una sveglia ricorrente ha le seguenti caratteristiche:

  • Un tipo di allarme. Per ulteriori discussioni, vedi Scegliere un tipo di sveglia.

  • Un'ora di attivazione. Se l'ora di attivazione 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 si attiva quando viene attivata l'allarme. Quando imposti una seconda sveglia che utilizza lo stesso intent in attesa, la sveglia originale viene sostituita.

Per annullare un PendingIntent(), passa FLAG_NO_CREATE a PendingIntent.getService() per ottenere un'istanza dell'intent (se esistente), poi passalo 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 nell'uso di una sveglia ricorrente è il tipo di sveglia.

Esistono due tipi di orologio generici 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 da parete). Ciò significa che il tempo reale trascorso è adatto per impostare una sveglia in base al tempo trascorso (ad esempio, una sveglia che si attiva ogni 30 secondi) poiché non è influenzata da fuso orario o impostazioni internazionali. Il tipo di orologio in tempo reale è più adatto alle sveglie che dipendono dalle impostazioni internazionali correnti.

Entrambi i tipi hanno una versione di "attivazione", che richiede di riattivare la CPU del dispositivo se lo schermo è spento. In questo modo la sveglia si attiverà all'ora programmata. È utile se la tua app ha una dipendenza di tempo. ad esempio se ha una finestra limitata per eseguire una particolare operazione. Se non utilizzi la versione per la riattivazione del tipo di sveglia, tutte le sveglie ripetute verranno attivate alla successiva attivazione del dispositivo.

Se desideri semplicemente che la sveglia si attivi a un determinato intervallo (ad esempio, ogni mezz'ora), utilizza uno dei tipi di tempo reale trascorso. In generale, questa è la scelta migliore.

Se desideri che la sveglia si attivi a una determinata ora del giorno, scegli uno dei tipi di orologio in tempo reale basati sull'orologio. Tuttavia, tieni presente che questo approccio può presentare alcuni svantaggi. L'app potrebbe non tradurre correttamente in altre lingue e se l'utente modifica l'impostazione dell'ora del dispositivo, potrebbe causare comportamenti imprevisti nell'app. Inoltre, l'utilizzo di un tipo di sveglia con orologio in tempo reale non funziona bene, come illustrato in precedenza. Ti consigliamo di utilizzare una sveglia "in tempo reale trascorso" se possibile.

Ecco l'elenco dei tipi:

  • ELAPSED_REALTIME: attiva l'intent in sospeso in base alla quantità di tempo trascorso dall'avvio del dispositivo, ma non lo riattiva. Il tempo trascorso include qualsiasi momento in cui il dispositivo è stato in sospensione.

  • ELAPSED_REALTIME_WAKEUP: riattiva il dispositivo e attiva l'intent in sospeso una volta trascorso il tempo specificato dall'avvio del dispositivo.

  • RTC: attiva l'intent in sospeso all'ora specificata, ma non riattiva il dispositivo.

  • RTC_WAKEUP: riattiva il dispositivo per attivare l'intent in sospeso all'ora specificata.

Esempi di sveglie in tempo reale trascorsi

Ecco alcuni esempi di utilizzo di ELAPSED_REALTIME_WAKEUP

Attiva il dispositivo per attivare l'allarme dopo 30 minuti, e successivamente ogni 30 minuti:

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

Riattiva il dispositivo per attivare una sveglia una tantum (non ripetuta) in 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 orologio in tempo reale

Ecco alcuni esempi di utilizzo di RTC_WAKEUP.

Attiva il dispositivo per attivare l'allarme alle 14:00 circa e ripeti 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);

Attiva il dispositivo per attivare l'allarme esattamente alle 8:30 e, successivamente, ogni 20 minuti:

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 quanto deve essere precisa la sveglia

Come descritto in precedenza, la scelta del tipo di allarme spesso è il primo passo nella creazione di una sveglia. Un'altra distinzione è la precisione della sveglia. Per la maggior parte delle app, setInexactRepeating() è la scelta giusta. Se utilizzi questo metodo, Android sincronizza più allarmi ripetuti inesatti e li attiva contemporaneamente. In questo modo si riduce il consumo della batteria.

Se possibile, evita di utilizzare sveglie esatte. Tuttavia, per l'app rara con requisiti di tempo rigidi, puoi impostare una sveglia esatta chiamando il numero setRepeating().

Con setInexactRepeating(), non puoi specificare un intervallo personalizzato come fai 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, puoi includere la possibilità di annullare la sveglia. Per annullare una sveglia, chiama cancel() su tue sveglie, passando il PendingIntent che non vuoi più attivare. Ecco alcuni esempi:

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 l'applicazione in modo che riavvii automaticamente una sveglia ricorrente se l'utente riavvia il dispositivo. Ciò garantisce che il dispositivo AlarmManager continui a eseguire la propria attività senza che l'utente debba riavviare manualmente il rilevatore.

Procedi nel seguente modo:

  1. Imposta l'autorizzazione RECEIVE_BOOT_COMPLETED nel file manifest dell'applicazione. Ciò consente alla tua app di ricevere l'elemento ACTION_BOOT_COMPLETED che viene trasmesso al termine 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"/>
  2. 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.
            }
        }
    }
    
  3. Aggiungi il destinatario al file manifest dell'app con un filtro per intent che filtra in base all'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>

    Nota che nel manifest, il ricevitore di avvio è impostato su android:enabled="false". Ciò significa che il destinatario non verrà chiamato a meno che l'applicazione non lo consenta esplicitamente. In questo modo si evita che il ricevitore di avvio venga chiamato inutilmente. 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 abilitato in questo modo, il ricevitore rimarrà attivo anche se l'utente riavvia il dispositivo. In altre parole, l'attivazione programmatica del ricevitore sostituisce l'impostazione del manifest, anche tra i riavvii. Il destinatario rimarrà attivo finché l'app non lo disattiverà. Puoi disattivare un ricevitore (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 sveglie mentre il dispositivo è in modalità Sospensione

I dispositivi con Android 6.0 (livello API 23) supportano la modalità Sospensione, che consente di prolungare la durata della batteria del dispositivo. Le sveglie non si attivano quando il dispositivo è in modalità Sospensione Le sveglie programmate vengono differite finché il dispositivo non disattiva questa modalità. Se devi completare il lavoro anche quando il dispositivo è inattivo, sono disponibili diverse opzioni:

best practice

Ogni scelta che fai nella progettazione della sveglia ripetuta può avere conseguenze sul modo in cui la tua app utilizza (o viola) le risorse di sistema. Ad esempio, immagina un'app molto popolare che si sincronizza con un server. Se l'operazione di sincronizzazione si basa sull'ora dell'orologio e ogni istanza dell'app si sincronizza alle 23:00, il carico sul server potrebbe comportare una latenza elevata o persino un "denial of service". Segui queste best practice per l'utilizzo delle sveglie:

  • Aggiungi casualità (jitter) a tutte le richieste di rete che si attivano in seguito a una sveglia ripetuta:

    • Eseguire operazioni locali quando si attiva l'allarme. Con "lavoro locale" si intende tutto ciò che non contatta un server o che non richiede i dati al server.

    • Allo stesso tempo, programma la sveglia che contiene le richieste di attivazione della rete in un periodo di tempo casuale.

  • Mantieni la frequenza della sveglia al minimo.

  • Non riattivare il dispositivo inutilmente (questo comportamento è determinato dal tipo di sveglia, come descritto nella sezione Scegliere un tipo di sveglia).

  • Non rendere l'ora di attivazione della sveglia più precisa del dovuto.

    Utilizza setInexactRepeating() anziché setRepeating(). Quando utilizzi setInexactRepeating(), Android sincronizza le sveglie ripetute da 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), tutti i rilevatori ripetuti sono sveglia inesatta. Tieni presente che, sebbene setInexactRepeating() rappresenti un miglioramento rispetto a setRepeating(), può comunque sovraccaricare un server se ogni istanza di un'app contatta il server più o meno nello stesso momento. Pertanto, per le richieste di rete, aggiungi un certo grado di casualità agli allarmi, come discusso in precedenza.

  • Se possibile, evita di basare la sveglia sull'ora dell'orologio.

    Le sveglie ripetute basate su un tempo di attivazione preciso non vengono ridimensionate correttamente. Se puoi, utilizza ELAPSED_REALTIME. I diversi tipi di allarme sono descritti in maggiore dettaglio nella sezione seguente.