Programmare sveglie

Le sveglie (basate sulla classe AlarmManager) ti consentono di eseguire operazioni basate sul tempo al di fuori del ciclo di vita dell'applicazione. Ad esempio, puoi utilizzare una sveglia per avviare un'operazione che richiede molto tempo, ad esempio avviare un servizio una volta al giorno per scaricare una previsione meteo.

Gli allarmi hanno le seguenti caratteristiche:

  • Ti consentono di attivare gli intent in orari e/o intervalli prestabiliti.

  • Puoi utilizzarli in combinazione con i 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 è in sospensione.

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

Impostare una sveglia approssimativa

Quando un'app imposta una sveglia imprecisa, il sistema la invia in un determinato momento futuro. Le sveglie imprecise forniscono alcune garanzie in merito alla tempistica di invio della sveglia, rispettando al contempo le limitazioni per il risparmio della batteria, come la modalità Sospensione.

Gli sviluppatori possono sfruttare le seguenti garanzie dell'API per personalizzare la tempistica di invio di allarmi imprecisi.

Inviare una sveglia dopo un orario specifico

Se la tua app chiama set(), setInexactRepeating() o setAndAllowWhileIdle(), la sveglia non suona mai prima dell'ora di attivazione specificata.

Su Android 12 (livello API 31) e versioni successive, il sistema richiama la sveglia entro un'ora dall'ora di attivazione specificata, a meno che non siano attive limitazioni per il risparmio energetico, come il risparmio energetico o la modalità Sospensione.

Inviare una sveglia durante un intervallo di tempo

Se la tua app chiama setWindow(), la sveglia non suona mai prima dell'ora di attivazione fornita. A meno che non siano in vigore limitazioni per il risparmio della batteria, l'avviso viene inviato nell'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'attivazione di una sveglia approssimativa con finestra temporale di almeno 10 minuti. Per questo motivo, i valori del parametro windowLengthMillis inferiori a 600000 vengono troncati a 600000.

Invia una sveglia ripetuta a intervalli approssimativamente regolari

Se la tua app chiama setInexactRepeating(), il sistema richiama più allarmi:

  1. La prima sveglia suona nell'intervallo di tempo specificato, a partire dall'ora di attivazione specificata.
  2. Le sveglie successive suonano in genere dopo il tempo specificato. Il tempo tra due invocazioni consecutive della sveglia può variare.

Impostare una sveglia esatta

Il sistema richiama un allarme esatto in un momento preciso in futuro.

La maggior parte delle app può pianificare attività ed eventi utilizzando sveglie imprecise per completare diversi casi d'uso comuni. Se la funzionalità di base della tua app dipende da una sveglia con timer preciso, ad esempio per un'app sveglia o un'app di 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 utili per gestire le operazioni di temporizzazione, ad esempio eseguire un'operazione ogni n secondi, mentre l'app è attiva: postAtTime() e postDelayed(). Tieni presente che queste API si basano sul tempo di attività del sistema e non sul tempo reale.
Attività pianificate in background, ad esempio l'aggiornamento dell'app e il caricamento dei log
WorkManager fornisce un modo per pianificare il lavoro periodico con tempistiche precise. Puoi fornire un intervallo di ripetizione e flexInterval (min 15 minuti) per definire il tempo di esecuzione granulare del lavoro.
Azione specificata dall'utente che deve avvenire dopo un momento specifico (anche se il sistema è in stato di inattività)
Utilizza una sveglia non esatta. Nello specifico, chiama setAndAllowWhileIdle().
Azione specificata dall'utente che deve avvenire dopo un'ora specifica
Utilizzare una sveglia non esatta. Nello specifico, chiama set().
Azione specificata dall'utente che può verificarsi in un determinato arco di tempo
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 precise utilizzando uno dei seguenti metodi. Questi metodi sono ordinati in modo che quelli più vicini alla fine dell'elenco servano per attività più critiche in termini di tempo, ma richiedano più risorse di sistema.

setExact()

Attivare una sveglia a un orario futuro quasi preciso, a condizione che non siano attive altre misure di risparmio batteria.

Utilizza questo metodo per impostare sveglie esatte, a meno che il funzionamento della tua app non sia urgente per l'utente.

setExactAndAllowWhileIdle()

Avvia una sveglia in un momento futuro quasi preciso, anche se sono attive misure di risparmio energetico.

setAlarmClock()

Avvia una sveglia a un'ora precisa in futuro. Poiché questi allarmi sono molto visibili agli utenti, il sistema non ne modifica mai la data di invio. Il sistema identifica queste sveglie come le più importanti e, se necessario, lascia le modalità a basso consumo per inviarle.

Consumo di risorse di sistema

Quando il sistema attiva gli allarmi esatti impostati dalla tua app, il dispositivo consuma molte risorse, ad esempio la durata della 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'sveglia imprecisa ogni volta che è possibile. Per eseguire un'attività più lunga, programmala utilizzando WorkManager o JobScheduler dal menuBroadcastReceiver della sveglia. Per eseguire operazioni mentre il dispositivo è in modalità Sospensione, crea una sveglia non esatta utilizzando setAndAllowWhileIdle() e avvia un job dalla sveglia.

Dichiara 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 tale scopo, dichiara l'autorizzazione SCHEDULE_EXACT_ALARM nel file manifest dell'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, hai la possibilità di 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 annuncino le stesse funzionalità, vengono concesse in modo diverso e supportano diversi casi d'uso. La tua app deve utilizzare sveglie esatte e dichiarare l'autorizzazione SCHEDULE_EXACT_ALARM o USE_EXACT_ALARM solo se una funzione rivolta agli utenti richiede azioni temporizzate in modo preciso.

USE_EXACT_ALARM

SCHEDULE_EXACT_ALARM

  • Concessa 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 pre-concessa per le nuove installazioni di app che hanno come target Android 13 (livello API 33) e versioni successive. Se un utente trasferisce i dati delle app su 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, verrà pre-concessa quando il dispositivo eseguirà l'upgrade ad Android 14.

Nota: se l'allarme esatto è impostato utilizzando un oggetto OnAlarmListener, ad esempio con l'API setExact, l'autorizzazione SCHEDULE_EXACT_ALARM non è richiesta.

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'autorizzazioneSCHEDULE_EXACT_ALARM.

Per verificare se l'autorizzazione è stata 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 dell'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. L'app deve implementare un ricevitore di trasmissione che svolga le seguenti operazioni:

  1. Conferma che la tua app dispone ancora dell'accesso speciale. Per farlo, chiama canScheduleExactAlarms(). Questo controllo protegge la tua app dal caso in cui l'utente conceda l'autorizzazione alla tua app, per poi revocarla quasi immediatamente dopo.
  2. Riprogramma le sveglie esatte di cui ha bisogno la 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.

Chiedi agli utenti di concedere l'autorizzazione SCHEDULE_EXACT_ALARM

L&#39;opzione si chiama &quot;Consenti l&#39;impostazione di sveglie e promemoria&quot;
Figura 1. Pagina Accesso speciale per le app "Sveglie e promemoria" nelle impostazioni di sistema, in cui gli utenti possono consentire alla tua app di impostare sveglie precise.

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é la tua app deve pianificare sveglie precise.
  2. Richiama un'intenzione che includa l'azione di intenzione ACTION_REQUEST_SCHEDULE_EXACT_ALARM.

Impostare una sveglia ripetuta

Le sveglie ripetute consentono al sistema di inviare notifiche alla tua app con una frequenza ricorrente.

Una sveglia progettata 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, tutte le sveglie ripetute sono sveglie imprecise.

Una sveglia ripetuta ha le seguenti caratteristiche:

  • Un tipo di sveglia. Per ulteriori informazioni, vedi Scegliere un tipo di avviso.

  • Un'ora di attivazione. Se l'ora di attivazione specificata è nel passato, la sveglia 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. Se imposti un secondo avviso che utilizza lo stesso intent in attesa, questo sostituisce l'avviso originale.

Per annullare un PendingIntent(), passa FLAG_NO_CREATE a PendingIntent.getService() per ottenere un'istanza dell'intent (se esistente), 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);
}

Scegli 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 il "tempo dall'avvio del sistema" come riferimento, 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 passare del tempo (ad esempio una sveglia che si attiva 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 "risveglio", che indica di riattivare la CPU del dispositivo se lo schermo è spento. In questo modo, la sveglia verrà attivata all'ora programmata. Questo è utile se la tua app ha una dipendenza dal tempo. Ad esempio, se ha un periodo di tempo limitato per eseguire una determinata operazione. Se non utilizzi la versione di sveglia del tipo di sveglia, tutte le sveglie ripetute verranno attivate al successivo risveglio del dispositivo.

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

Se vuoi che la sveglia venga attivata in un determinato momento della giornata, scegli uno dei tipi di orologio in tempo reale basati sull'orologio. Tieni presente, tuttavia, che questo approccio può avere alcuni svantaggi. L'app potrebbe non essere tradotta bene in altre lingue e, se l'utente modifica l'impostazione dell'ora del dispositivo, potrebbe verificarsi un comportamento imprevisto nell'app. Anche l'utilizzo di un tipo di sveglia con orologio in tempo reale non è scalabile, come discusso sopra. Se puoi, ti consigliamo di utilizzare una sveglia "in tempo reale trascorso".

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 il tempo durante il quale il dispositivo era in modalità Sospensione.

  • ELAPSED_REALTIME_WAKEUP: attiva il dispositivo e attiva l'intent in attesa dopo il 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 trascorse

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

Riattiva il dispositivo per attivare 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 da quel momento in poi:

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 sveglia è spesso il primo passaggio 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 ripetute imprecise e le attiva contemporaneamente. In questo modo si riduce il consumo della batteria.

Se possibile, evita di utilizzare sveglie esatte. Tuttavia, per le rare app con 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. Per l'elenco completo, visita la pagina AlarmManager.

Annulla una sveglia

A seconda dell'app, ti consigliamo di includere la possibilità di annullare la sveglia. Per annullare una sveglia, chiama cancel() in Alarm Manager, passando il valore 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 l'applicazione in modo da riavviare automaticamente una sveglia ripetuta se l'utente riavvia il dispositivo. In questo modo, AlarmManager continuerà a svolgere la sua attività senza che l'utente debba riavviare manualmente l'antifurto.

Procedi nel seguente modo:

  1. Imposta l'autorizzazione RECEIVE_BOOT_COMPLETED nel file manifest dell'applicazione. In questo modo, la tua app può ricevere il messaggio ACTION_BOOT_COMPLETED 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 della tua 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>

    Tieni presente che nel file manifest, il destinatario di avvio è impostato su android:enabled="false". Ciò significa che il ricevitore non verrà chiamato a meno che l'applicazione non lo abiliti esplicitamente. In questo modo, il ricevitore di avvio non viene 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 attivato in questo modo, il ricevitore rimarrà attivo anche se l'utente riavvia il dispositivo. In altre parole, l'attivazione del ricevitore tramite codice premetterà di ignorare l'impostazione del file manifest, anche dopo i riavvii. Il ricevitore rimarrà attivo finché l'app non lo disattiva. 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);

Attivare le sveglie quando il dispositivo è in modalità Sospensione

I dispositivi con Android 6.0 (livello API 23) supportano la modalità Sospensione, che contribuisce a prolungare la durata della batteria del dispositivo. Le sveglie non vengono attivate quando il dispositivo è in modalità Sospensione. Qualsiasi sveglia programmata viene posticipata finché il dispositivo non esce dalla modalità Sospensione. Se devi completare un lavoro anche quando il dispositivo è inattivo, hai a disposizione diverse opzioni:

  • Imposta una sveglia esatta.

  • Utilizza l'API WorkManager, progettata per eseguire attività in background. Puoi indicare che il sistema deve velocizzare il tuo lavoro in modo che venga completato il prima possibile. Per ulteriori informazioni, consulta Pianificare le attività con WorkManager

Best practice

Ogni scelta che fai durante la 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 popolare che si sincronizza con un server. Se l'operazione di sincronizzazione si basa sull'ora sulla data e ogni istanza dell'app si sincronizza alle 23:00, il carico sul server potrebbe comportare una latenza elevata o persino un "attacco di denial of service". Segui queste best practice per l'utilizzo delle sveglie:

  • Aggiungi casualità (jitter) a qualsiasi richiesta di rete attivata come risultato di una sveglia ripetuta:

    • Eseguire qualsiasi operazione locale quando si attiva l'allarme. Per "lavoro locale" si intende qualsiasi attività che non acceda a un server o che non richieda i dati del server.

    • Allo stesso tempo, pianifica l'attivazione della sveglia contenente le richieste di rete in un periodo di tempo casuale.

  • Riduci al minimo la frequenza delle sveglie.

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

  • Non impostare l'ora di attivazione della sveglia più precisa del necessario.

    Utilizza setInexactRepeating() invece di setRepeating(). Quando usi setInexactRepeating(), 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 ripetute sono sveglie imprecise. Tieni presente che, anche se setInexactRepeating() è un miglioramento rispetto a setRepeating(), può comunque sopraffare un server se ogni istanza di un'app accede al server contemporaneamente. Pertanto, per le richieste di rete, aggiungi un po' di casualità ai tuoi avvisi, come discusso in precedenza.

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

    Le sveglie ricorrenti basate su un'ora di attivazione precisa non si adattano bene. Se possibile, utilizza ELAPSED_REALTIME. I diversi tipi di sveglie sono descritti in maggiore dettaglio nella sezione seguente.