Le app per Android inviano e ricevono messaggi di trasmissione dal sistema Android e da altre app per Android, in modo simile al pattern di progettazione publish-subscribe. In genere, il sistema e le app inviano trasmissioni quando si verificano determinati eventi. Ad esempio, il sistema Android invia trasmissioni quando si verificano vari eventi di sistema, come l'avvio del sistema o la ricarica del dispositivo. Le app inviano anche trasmissioni personalizzate, ad esempio per notificare ad altre app qualcosa che potrebbe interessarle (ad esempio, il download di nuovi dati).
Le app possono registrarsi per ricevere trasmissioni specifiche. Quando viene inviata una trasmissione, il sistema la indirizza automaticamente alle app che hanno sottoscritto la ricezione di quel particolare tipo di trasmissione.
In generale, le trasmissioni possono essere utilizzate come sistema di messaggistica tra le app e al di fuori del normale flusso utente. Tuttavia, devi fare attenzione a non abusare dell'opportunità di rispondere alle trasmissioni ed eseguire job in background che possono contribuire a rallentare le prestazioni del sistema.
Informazioni sulle trasmissioni di sistema
Il sistema invia automaticamente le trasmissioni quando si verificano vari eventi di sistema, ad esempio quando il sistema passa alla modalità aereo e viceversa. Tutte le app sottoscritte ricevono queste trasmissioni.
L'oggetto Intent racchiude l'annuncio. La stringa action identifica
l'evento che si è verificato, ad esempio android.intent.action.AIRPLANE_MODE. L'intent potrebbe includere anche informazioni aggiuntive raggruppate nel relativo campo extra.
Ad esempio, l'intent della modalità aereo include un extra booleano che indica se la modalità aereo è attiva o meno.
Per saperne di più su come leggere gli intent e ottenere la stringa dell'azione da un intent, consulta Intent e filtri di intent.
Azioni di trasmissione di sistema
Per un elenco completo delle azioni di annuncio di sistema, consulta il file BROADCAST_ACTIONS.TXT nell'SDK Android. A ogni azione di trasmissione è associato un campo costante. Ad esempio, il valore della costante
ACTION_AIRPLANE_MODE_CHANGED è android.intent.action.AIRPLANE_MODE.
La documentazione per ogni azione di trasmissione è disponibile nel campo costante associato.
Modifiche alle trasmissioni di sistema
Man mano che la piattaforma Android si evolve, cambia periodicamente il comportamento delle trasmissioni di sistema. Tieni presente le seguenti modifiche per supportare tutte le versioni di Android.
Android 16
In Android 16, l'ordine di pubblicazione delle trasmissioni che utilizzano l'android:priority
attributo o IntentFilter.setPriority() in processi diversi
non sarà garantito. Le priorità di trasmissione vengono rispettate solo all'interno dello stesso processo dell'applicazione, anziché in tutti i processi.
Inoltre, le priorità di trasmissione vengono automaticamente limitate all'intervallo
(SYSTEM_LOW_PRIORITY + 1, SYSTEM_HIGH_PRIORITY - 1).
Solo i componenti di sistema possono impostare SYSTEM_LOW_PRIORITY, SYSTEM_HIGH_PRIORITY come priorità di trasmissione.
Android 14
Mentre le app sono in uno stato di cache, il sistema ottimizza la pubblicazione delle trasmissioni
per l'integrità del sistema. Ad esempio, il sistema posticipa le trasmissioni di sistema meno importanti
, come ACTION_SCREEN_ON, mentre l'app è in stato di cache.
Una volta che l'app passa dallo stato di cache a un ciclo di vita del processo attivo,
il sistema pubblica tutte le trasmissioni posticipate.
Le trasmissioni importanti che sono dichiarate nel manifest rimuovono temporaneamente le app dallo stato di cache per la pubblicazione.
Android 9
A partire da Android 9 (livello API 28), la NETWORK_STATE_CHANGED_ACTION
trasmissione non riceve informazioni sulla posizione dell'utente o dati che consentono l'identificazione
personale.
Se la tua app è installata su un dispositivo con Android 9.0 (livello API 28) o versioni successive, il sistema non include SSID, BSSID, informazioni sulla connessione o risultati della scansione nelle trasmissioni Wi-Fi. Per ottenere queste informazioni, chiama
getConnectionInfo() invece.
Android 8.0
A partire da Android 8.0 (livello API 26), il sistema impone ulteriori limitazioni ai ricevitori dichiarati nel manifest.
Se la tua app ha come target Android 8.0 o versioni successive, non puoi utilizzare il manifest per dichiarare un ricevitore per la maggior parte delle trasmissioni implicite (trasmissioni che non hanno come target specifico la tua app). Puoi comunque utilizzare un ricevitore registrato nel contesto quando l'utente utilizza attivamente la tua app.
Android 7.0
Android 7.0 (livello API 24) e versioni successive non inviano le seguenti trasmissioni di sistema:
Inoltre, le app che hanno come target Android 7.0 e versioni successive devono registrare la
CONNECTIVITY_ACTION trasmissione utilizzando
registerReceiver(BroadcastReceiver, IntentFilter). La dichiarazione di un ricevitore nel manifest non funziona.
Ricevere trasmissioni
Le app possono ricevere trasmissioni in due modi: tramite ricevitori registrati nel contesto e ricevitori dichiarati nel manifest.
Ricevitori registrati nel contesto
I ricevitori registrati nel contesto ricevono le trasmissioni finché il contesto di registrazione è valido. In genere, questo avviene tra le chiamate a registerReceiver e
unregisterReceiver. Il contesto di registrazione diventa non valido anche quando il sistema distrugge il contesto corrispondente. Ad esempio, se ti registri in un contesto
Activity, ricevi le trasmissioni finché l'attività
rimane attiva. Se ti registri con il contesto dell'applicazione, ricevi le trasmissioni finché l'app è in esecuzione.
Per registrare un ricevitore con un contesto:
Nel file build a livello di modulo dell'app, includi la versione 1.9.0 o successive di la libreria AndroidX Core:
Groovy
dependencies { def core_version = "1.18.0" // Java language implementation implementation "androidx.core:core:$core_version" // Kotlin implementation "androidx.core:core-ktx:$core_version" // To use RoleManagerCompat implementation "androidx.core:core-role:1.1.0" // To use the Animator APIs implementation "androidx.core:core-animation:1.0.0" // To test the Animator APIs androidTestImplementation "androidx.core:core-animation-testing:1.0.0" // Optional - To enable APIs that query the performance characteristics of GMS devices. implementation "androidx.core:core-performance:1.0.0" // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google implementation "androidx.core:core-google-shortcuts:1.1.0" // Optional - to support backwards compatibility of RemoteViews implementation "androidx.core:core-remoteviews:1.1.0" // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 implementation "androidx.core:core-splashscreen:1.2.0" }
Kotlin
dependencies { val core_version = "1.18.0" // Java language implementation implementation("androidx.core:core:$core_version") // Kotlin implementation("androidx.core:core-ktx:$core_version") // To use RoleManagerCompat implementation("androidx.core:core-role:1.1.0") // To use the Animator APIs implementation("androidx.core:core-animation:1.0.0") // To test the Animator APIs androidTestImplementation("androidx.core:core-animation-testing:1.0.0") // Optional - To enable APIs that query the performance characteristics of GMS devices. implementation("androidx.core:core-performance:1.0.0") // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google implementation("androidx.core:core-google-shortcuts:1.1.0") // Optional - to support backwards compatibility of RemoteViews implementation("androidx.core:core-remoteviews:1.1.0") // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 implementation("androidx.core:core-splashscreen:1.2.0") }
Crea un'istanza di
BroadcastReceiver:Kotlin
val myBroadcastReceiver = MyBroadcastReceiver()Java
MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();Crea un'istanza di
IntentFilter:Kotlin
val filter = IntentFilter("com.example.snippets.ACTION_UPDATE_DATA")Java
IntentFilter filter = new IntentFilter("com.example.snippets.ACTION_UPDATE_DATA");Scegli se il broadcast receiver deve essere esportato e visibile ad altre app sul dispositivo. Se questo ricevitore è in ascolto delle trasmissioni inviate dal sistema o da altre app, anche altre app di tua proprietà, utilizza il flag
RECEIVER_EXPORTED. Se invece questo ricevitore è in ascolto solo delle trasmissioni inviate dalla tua app, utilizza il flagRECEIVER_NOT_EXPORTED.Kotlin
val listenToBroadcastsFromOtherApps = false val receiverFlags = if (listenToBroadcastsFromOtherApps) { ContextCompat.RECEIVER_EXPORTED } else { ContextCompat.RECEIVER_NOT_EXPORTED }Java
boolean listenToBroadcastsFromOtherApps = false; int receiverFlags = listenToBroadcastsFromOtherApps ? ContextCompat.RECEIVER_EXPORTED : ContextCompat.RECEIVER_NOT_EXPORTED;Registra il ricevitore chiamando
registerReceiver():Kotlin
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags)Java
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags);Per interrompere la ricezione delle trasmissioni, chiama
unregisterReceiver(android.content.BroadcastReceiver). Assicurati di annullare la registrazione del ricevitore quando non ne hai più bisogno o il contesto non è più valido.
Annullare la registrazione del broadcast receiver
Mentre il broadcast receiver è registrato, mantiene un riferimento al contesto con cui l'hai registrato. Ciò può potenzialmente causare perdite se l'ambito registrato del ricevitore supera l'ambito del ciclo di vita del contesto. Ad esempio, questo può verificarsi quando registri un ricevitore nell'ambito di un'attività, ma ti dimentichi di annullare la registrazione quando il sistema distrugge l'attività. Pertanto, annulla sempre la registrazione del broadcast receiver.
Kotlin
class MyActivity : ComponentActivity() {
private val myBroadcastReceiver = MyBroadcastReceiver()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...
ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags)
setContent { MyApp() }
}
override fun onDestroy() {
super.onDestroy()
// When you forget to unregister your receiver here, you're causing a leak!
this.unregisterReceiver(myBroadcastReceiver)
}
}
Java
class MyActivity extends ComponentActivity {
MyBroadcastReceiver myBroadcastReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags);
// Set content
}
}
Registrare i ricevitori nell'ambito più piccolo
Il broadcast receiver deve essere registrato solo quando sei effettivamente interessato al risultato. Scegli l'ambito del ricevitore più piccolo possibile:
LifecycleResumeEffecto metodi del ciclo di vitaonResume/onPausedell'attività: il broadcast receiver riceve gli aggiornamenti solo quando l'app è in stato di ripresa.LifecycleStartEffecto metodi del ciclo di vitaonStart/onStopdell'attività: il broadcast receiver riceve gli aggiornamenti solo quando l'app è in stato di ripresa.DisposableEffect: il broadcast receiver riceve gli aggiornamenti solo quando il componibile si trova nell'albero di composizione. Questo ambito non è collegato all'ambito del ciclo di vita dell'attività. Valuta la possibilità di registrare il ricevitore nel contesto dell'applicazione. Questo perché il componibile potrebbe teoricamente sopravvivere all'ambito del ciclo di vita dell'attività e causare una perdita di memoria dell'attività.onCreate/onDestroydell'attività: il broadcast receiver riceve gli aggiornamenti mentre l'attività è in stato di creazione. Assicurati di annullare la registrazione inonDestroy()e non inonSaveInstanceState(Bundle)perché potrebbe non essere chiamato.- Un ambito personalizzato: ad esempio, puoi registrare un ricevitore nell'ambito di
ViewModel, in modo che sopravviva alla ricreazione dell'attività. Assicurati di utilizzare il contesto dell'applicazione per registrare il ricevitore, poiché il ricevitore può sopravvivere all'ambito del ciclo di vita dell'attività e causare una perdita di memoria dell'attività.
Creare un componibile stateful e stateless
Compose ha componibili stateful e stateless. La registrazione o l'annullamento della registrazione di un broadcast receiver all'interno di un componibile lo rende stateful. Il componibile non è una funzione deterministica che esegue il rendering degli stessi contenuti quando vengono passati gli stessi parametri. Lo stato interno può cambiare in base alle chiamate al broadcast receiver registrato.
Come best practice in Compose, ti consigliamo di dividere i componibili in versioni stateful e stateless. Pertanto, ti consigliamo di spostare la creazione del broadcast receiver da un componibile per renderlo stateless:
@Composable
fun MyStatefulScreen() {
val myBroadcastReceiver = remember { MyBroadcastReceiver() }
val context = LocalContext.current
LifecycleStartEffect(true) {
// ...
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, flags)
onStopOrDispose { context.unregisterReceiver(myBroadcastReceiver) }
}
MyStatelessScreen()
}
@Composable
fun MyStatelessScreen() {
// Implement your screen
}
Ricevitori dichiarati nel manifest
Se dichiari un broadcast receiver nel manifest, il sistema avvia l'app quando viene inviata la trasmissione. Se l'app non è già in esecuzione, il sistema la avvia.
Per dichiarare un broadcast receiver nel manifest:
Specifica l'elemento
<receiver>nel manifest dell'app.<!-- If this receiver listens for broadcasts sent from the system or from other apps, even other apps that you own, set android:exported to "true". --> <receiver android:name=".MyBroadcastReceiver" android:exported="false"> <intent-filter> <action android:name="com.example.snippets.ACTION_UPDATE_DATA" /> </intent-filter> </receiver>I filtri di intent specificano le azioni di trasmissione a cui è sottoscritto il ricevitore.
Crea una sottoclasse di
BroadcastReceivere implementaonReceive(Context, Intent). Il broadcast receiver nell'esempio seguente registra e visualizza i contenuti della trasmissione:Kotlin
class MyBroadcastReceiver : BroadcastReceiver() { @Inject lateinit var dataRepository: DataRepository override fun onReceive(context: Context, intent: Intent) { if (intent.action == "com.example.snippets.ACTION_UPDATE_DATA") { val data = intent.getStringExtra("com.example.snippets.DATA") ?: "No data" // Do something with the data, for example send it to a data repository: dataRepository.updateData(data) } } }Java
public static class MyBroadcastReceiver extends BroadcastReceiver { @Inject DataRepository dataRepository; @Override public void onReceive(Context context, Intent intent) { if (Objects.equals(intent.getAction(), "com.example.snippets.ACTION_UPDATE_DATA")) { String data = intent.getStringExtra("com.example.snippets.DATA"); // Do something with the data, for example send it to a data repository: if (data != null) { dataRepository.updateData(data); } } } }
Il gestore dei pacchetti di sistema registra il ricevitore quando l'app viene installata. Il ricevitore diventa quindi un punto di ingresso separato nell'app, il che significa che il sistema può avviare l'app e pubblicare la trasmissione se l'app non è in esecuzione.
Il sistema crea un nuovo BroadcastReceiver oggetto componente per gestire
ogni trasmissione che riceve. Questo oggetto è valido solo per la durata di
la chiamata a onReceive(Context, Intent). Una volta che il codice restituisce questo metodo, il sistema considera il componente non più attivo.
Effetti sullo stato del processo
Il funzionamento o meno di BroadcastReceiver influisce sul processo contenuto, che può alterare la probabilità di eliminazione del sistema. Un processo in primo piano
esegue il metodo onReceive() di un ricevitore. Il sistema esegue il processo tranne in caso di pressione di memoria estrema.
Il sistema disattiva BroadcastReceiver dopo onReceive().
L'importanza del processo host del ricevitore dipende dai componenti dell'app. Se questo processo ospita solo un ricevitore dichiarato nel manifest, il sistema potrebbe eliminarlo dopo onReceive() per liberare risorse per altri processi più critici. Questo è comune per le app con cui l'utente non ha interagito o non ha interagito di recente.
Pertanto, i broadcast receiver non devono avviare thread in background a lunga esecuzione.
Il sistema può interrompere il processo in qualsiasi momento dopo onReceive() per recuperare memoria, terminando il thread creato. Per mantenere attivo il processo, pianifica un
JobService dal ricevitore utilizzando JobScheduler in modo che il
sistema sappia che il processo è ancora in esecuzione. La panoramica del lavoro in background
fornisce ulteriori dettagli.
Inviare trasmissioni
Android offre due modi per le app di inviare trasmissioni:
- Il metodo
sendOrderedBroadcast(Intent, String)invia le trasmissioni a un ricevitore alla volta. Man mano che ogni ricevitore viene eseguito a turno, può propagare un risultato al ricevitore successivo. Può anche interrompere completamente la trasmissione in modo che non raggiunga altri ricevitori. Puoi controllare l'ordine di esecuzione dei ricevitori all'interno dello stesso processo dell'app. Per farlo, utilizza l'attributoandroid:prioritydel filtro di intent corrispondente. I ricevitori con la stessa priorità vengono eseguiti in un ordine arbitrario. - Il metodo
sendBroadcast(Intent)invia le trasmissioni a tutti i ricevitori in un ordine non definito. Questa è chiamata trasmissione normale. È più efficiente, ma significa che i ricevitori non possono leggere i risultati di altri ricevitori, propagare i dati ricevuti dalla trasmissione o interrompere la trasmissione.
Il seguente snippet di codice mostra come inviare una trasmissione creando un
intent e chiamando sendBroadcast(Intent).
Kotlin
val intent = Intent("com.example.snippets.ACTION_UPDATE_DATA").apply {
putExtra("com.example.snippets.DATA", newData)
setPackage("com.example.snippets")
}
context.sendBroadcast(intent)
Java
Intent intent = new Intent("com.example.snippets.ACTION_UPDATE_DATA");
intent.putExtra("com.example.snippets.DATA", newData);
intent.setPackage("com.example.snippets");
context.sendBroadcast(intent);
L'annuncio è racchiuso in un Intent oggetto. La stringa action dell'intent deve fornire la sintassi del nome del pacchetto Java dell'app e identificare in modo univoco l'evento di trasmissione. Puoi allegare informazioni aggiuntive all'
intent con putExtra(String, Bundle). Puoi anche limitare una trasmissione a
un insieme di app nella stessa organizzazione chiamando setPackage(String) su
l'intent.
Limitare le trasmissioni con le autorizzazioni
Le autorizzazioni ti consentono di limitare le trasmissioni all'insieme di app che dispongono di determinate autorizzazioni. Puoi applicare limitazioni al mittente o al ricevitore di una trasmissione.
Inviare trasmissioni con le autorizzazioni
Quando chiami sendBroadcast(Intent, String) o
sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String,
Bundle)
, puoi specificare un parametro di autorizzazione. Solo i ricevitori che hanno richiesto questa
autorizzazione con il tag <uses-permission> nel manifest possono ricevere la
trasmissione. Se l'autorizzazione è pericolosa, devi concederla prima che il ricevitore possa ricevere la trasmissione. Ad esempio, il seguente codice invia una trasmissione con un'autorizzazione:
Kotlin
context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION)
Java
context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION);
Per ricevere la trasmissione, l'app di ricezione deve richiedere l'autorizzazione nel seguente modo:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Puoi specificare un'autorizzazione di sistema esistente, ad esempio
BLUETOOTH_CONNECT o definire un'autorizzazione personalizzata con l'elemento
<permission>. Per informazioni sulle autorizzazioni e sulla sicurezza in
generale, consulta le Autorizzazioni di sistema.
Ricevere trasmissioni con le autorizzazioni
Se specifichi un parametro di autorizzazione quando registri un broadcast receiver
(con
registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) o nel
<receiver> tag nel manifest), solo i broadcaster che hanno
richiesto l'autorizzazione con il <uses-permission> tag nel loro
manifest possono inviare un intent al ricevitore. Se l'autorizzazione è pericolosa, deve essere concessa anche al broadcaster.
Ad esempio, supponiamo che l'app di ricezione abbia un ricevitore dichiarato nel manifest come segue:
<!-- If this receiver listens for broadcasts sent from the system or from
other apps, even other apps that you own, set android:exported to "true". -->
<receiver
android:name=".MyBroadcastReceiverWithPermission"
android:permission="android.permission.ACCESS_COARSE_LOCATION"
android:exported="true">
<intent-filter>
<action android:name="com.example.snippets.ACTION_UPDATE_DATA" />
</intent-filter>
</receiver>
Oppure l'app di ricezione ha un ricevitore registrato nel contesto come segue:
Kotlin
ContextCompat.registerReceiver(
context, myBroadcastReceiver, filter,
android.Manifest.permission.ACCESS_COARSE_LOCATION,
null, // scheduler that defines thread, null means run on main thread
receiverFlags
)
Java
ContextCompat.registerReceiver(
context, myBroadcastReceiver, filter,
android.Manifest.permission.ACCESS_COARSE_LOCATION,
null, // scheduler that defines thread, null means run on main thread
receiverFlags
);
Per poter inviare trasmissioni a questi ricevitori, l'app di invio deve richiedere l'autorizzazione nel seguente modo:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Considerazioni sulla sicurezza
Di seguito sono riportate alcune considerazioni sulla sicurezza per l'invio e la ricezione di trasmissioni:
Se molte app hanno registrato la ricezione della stessa trasmissione nel manifest, il sistema potrebbe avviare molte app, con un impatto significativo sulle prestazioni del dispositivo e sull'esperienza utente. Per evitare questo problema, preferisci utilizzare la registrazione del contesto rispetto alla dichiarazione del manifest. A volte, il sistema Android stesso impone l'utilizzo di ricevitori registrati nel contesto. Ad esempio, la trasmissione
CONNECTIVITY_ACTIONviene pubblicata solo sui ricevitori registrati nel contesto.Non trasmettere informazioni sensibili utilizzando un intent implicito. Qualsiasi app può leggere le informazioni se si registra per ricevere la trasmissione. Esistono tre modi per controllare chi può ricevere le tue trasmissioni:
- Puoi specificare un'autorizzazione quando invii una trasmissione.
- In Android 4.0 (livello API 14) e versioni successive, puoi specificare un
pacchetto con
setPackage(String)quando invii una trasmissione. Il sistema limita la trasmissione all'insieme di app che corrispondono al pacchetto.
Quando registri un ricevitore, qualsiasi app può inviare trasmissioni potenzialmente dannose al ricevitore della tua app. Esistono diversi modi per limitare le trasmissioni ricevute dalla tua app:
- Puoi specificare un'autorizzazione quando registri un broadcast receiver.
- Per i ricevitori dichiarati nel manifest, puoi impostare l'attributo android:exported su "false" nel manifest. Il ricevitore non riceve trasmissioni da origini esterne all'app.
Lo spazio dei nomi per le azioni di trasmissione è globale. Assicurati che i nomi delle azioni e le altre stringhe siano scritte in uno spazio dei nomi di tua proprietà. In caso contrario, potresti inavvertitamente entrare in conflitto con altre app.
Poiché il metodo
onReceive(Context, Intent)di un ricevitore viene eseguito sul thread principale, deve essere eseguito e restituito rapidamente. Se devi eseguire un lavoro a lunga esecuzione, fai attenzione a generare thread o avviare servizi in background perché il sistema può eliminare l'intero processo dopo la restituzione dionReceive(). Per saperne di più, consulta Effetto sullo stato del processo Per eseguire un lavoro a lunga esecuzione, ti consigliamo di:- Chiamare
goAsync()nel metodoonReceive()del ricevitore e passareBroadcastReceiver.PendingResulta un thread in background. In questo modo la trasmissione rimane attiva dopo la restituzione dionReceive(). Tuttavia, anche con questo approccio il sistema si aspetta che tu completi la trasmissione molto rapidamente (in meno di 10 secondi). Ti consente di spostare il lavoro su un altro thread per evitare di bloccare il thread principale. - Pianificare un job con il
JobScheduler. Per saperne di più, consulta Pianificazione intelligente dei job.
- Chiamare
Non avviare attività dai broadcast receiver perché l'esperienza utente è fastidiosa, soprattutto se sono presenti più ricevitori. In alternativa, valuta la possibilità di mostrare una notifica.