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 pubblica-sottoscrivi. Il sistema e le app in genere 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 inviato un broadcast, il sistema lo indirizza automaticamente alle app che hanno eseguito la sottoscrizione per ricevere quel particolare tipo di broadcast.
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 e di eseguire processi in background che possono contribuire a un rallentamento delle prestazioni del sistema.
Informazioni sugli annunci di sistema
Il sistema invia automaticamente trasmissioni quando si verificano vari eventi di sistema, ad esempio quando il sistema attiva e disattiva la modalità aereo. Tutte le app a cui è stato effettuato l'abbonamento 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 campo extra.
Ad esempio, l'intent 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 di azione da un intent, consulta Intent e filtri per 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 distribuzione delle trasmissioni utilizzando l'attributo android:priority o IntentFilter.setPriority() in processi diversi non sarà garantito. Le priorità di trasmissione vengono rispettate solo
all'interno della stessa procedura di candidatura, non in tutte le procedure.
Inoltre, le priorità di trasmissione sono 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
Quando le app sono in stato memorizzato nella cache, il sistema ottimizza la distribuzione della trasmissione
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 memorizzato nella cache.
Una volta che l'app passa dallo stato memorizzato nella cache a un ciclo di vita del processo attivo,
il sistema distribuisce le trasmissioni differite.
Le trasmissioni importanti dichiarate nel manifest rimuovono temporaneamente le app dallo stato memorizzato nella cache per la distribuzione.
Android 9
A partire da Android 9 (livello API 28), la trasmissione NETWORK_STATE_CHANGED_ACTION non riceve informazioni sulla posizione dell'utente o dati personali identificabili.
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
il numero getConnectionInfo().
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 file manifest per dichiarare un ricevitore per la maggior parte delle trasmissioni implicite (trasmissioni che non hanno come target specificamente 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 trasmissione
CONNECTIVITY_ACTION utilizzando
registerReceiver(BroadcastReceiver, IntentFilter). La dichiarazione di un ricevitore
nel manifest non funziona.
Ricevere trasmissioni
Le app possono ricevere broadcast in due modi: tramite i ricevitori registrati nel contesto e i 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. Anche il contesto di registrazione diventa non valido 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 registri il contesto dell'applicazione, ricevi
trasmissioni finché l'app è in esecuzione.
Per registrare un ricevitore con un contesto:
Nel file di build a livello di modulo della tua app, includi la versione 1.9.0 o successive della libreria AndroidX Core:
Groovy
dependencies { def core_version = "1.19.1" // 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.19.1" // 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 di 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 destinatario chiamando il numero
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 ti serve più o il contesto non è più valido.
Annullare la registrazione del broadcast receiver
Mentre il broadcast receiver è registrato, contiene un riferimento al contesto con cui è stato registrato. Ciò può potenzialmente causare perdite se l'ambito registrato del destinatario supera l'ambito del ciclo di vita del contesto. Ad esempio, questo può verificarsi quando registri un ricevitore in un ambito di attività, ma 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
}
}
Registra i ricevitori nell'ambito più piccolo
Il broadcast receiver deve essere registrato solo quando sei effettivamente interessato al risultato. Scegli l'ambito del destinatario più piccolo possibile:
- Metodi del ciclo di vita
LifecycleResumeEffecto dell'attivitàonResume/onPause: il broadcast receiver riceve gli aggiornamenti solo quando l'app è nello stato di ripresa. - Metodi del ciclo di vita
LifecycleStartEffecto dell'attivitàonStart/onStop: il broadcast receiver riceve gli aggiornamenti solo quando l'app è nello stato di ripresa. DisposableEffect: il broadcast receiver riceve aggiornamenti solo mentre il composable si trova nell'albero di composizione. Questo ambito non è collegato all'ambito del ciclo di vita dell'attività. Valuta la possibilità di registrare il destinatario nel contesto dell'applicazione. Questo perché il composable potrebbe teoricamente sopravvivere all'ambito del ciclo di vita dell'attività e causare una perdita di memoria.- Attività
onCreate/onDestroy: il broadcast receiver riceve aggiornamenti mentre l'attività è nello stato creato. Assicurati di annullare la registrazione inonDestroy()e non inonSaveInstanceState(Bundle)perché questa potrebbe non essere chiamata. - Un ambito personalizzato: ad esempio, puoi registrare un ricevitore nell'ambito
ViewModelin 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.
Crea composable stateful e stateless
Compose ha composable stateful e stateless. La registrazione o l'annullamento della registrazione di un broadcast receiver all'interno di un composable lo rende stateful. Il composable non è una funzione deterministica che esegue il rendering dello stesso contenuto quando vengono passati gli stessi parametri. Lo stato interno può cambiare in base alle chiamate al ricevitore di trasmissione registrato.
Come best practice in Compose, ti consigliamo di dividere i composable in versioni con stato e senza stato. Pertanto, ti consigliamo di estrarre la creazione del broadcast receiver da un elemento 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 la tua app quando viene inviato il broadcast. Se l'app non è già in esecuzione, il sistema la avvia.
Per dichiarare un broadcast receiver nel manifest, segui questi passaggi:
Specifica l'elemento
<receiver>nel manifest della tua 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 per intent specificano le azioni di trasmissione a cui si iscrive il ricevitore.
Sottoclasse
BroadcastReceivere implementaonReceive(Context, Intent). Il broadcast receiver nel seguente esempio registra e mostra 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 di pacchetti di sistema registra il ricevitore quando l'app viene installata. Il ricevitore diventa quindi un punto di accesso separato all'app, il che significa che il sistema può avviare l'app e inviare la trasmissione se l'app non è in esecuzione.
Il sistema crea un nuovo oggetto componente BroadcastReceiver per gestire
ogni trasmissione che riceve. Questo oggetto è valido solo per la durata
della chiamata a onReceive(Context, Intent). Una volta che il codice viene restituito da questo
metodo, il sistema considera il componente non più attivo.
Effetti sullo stato del processo
Il funzionamento o meno del BroadcastReceiver influisce sul processo
contenuto, che può alterare la probabilità di arresto del sistema. Un processo in primo piano
esegue il metodo onReceive() di un ricevitore. Il sistema esegue la procedura
tranne in condizioni di pressione di memoria estrema.
Il sistema disattiva BroadcastReceiver dopo onReceive().
L'importanza del processo host del destinatario dipende dai componenti dell'app. Se questo processo ospita
solo un ricevitore dichiarato nel manifest, il sistema potrebbe terminarlo dopo onReceive()
per liberare risorse per altri processi più critici. Questo è comune per le app con cui l'utente non ha mai interagito o non ha interagito di recente.
Pertanto, i ricevitori di trasmissione non devono avviare thread in background di lunga durata.
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 destinatario utilizzando JobScheduler in modo che
il sistema sappia che il processo è ancora in corso. Panoramica del lavoro in background
fornisce ulteriori dettagli.
Inviare trasmissioni
Android offre due modi per inviare trasmissioni dalle app:
- 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 in cui vengono eseguiti i ricevitori all'interno dello stesso processo dell'app. A questo scopo, utilizza l'attributoandroid:prioritydell'intent-filter corrispondente. I ricevitori con la stessa priorità vengono eseguiti in un ordine arbitrario. - Il metodo
sendBroadcast(Intent)invia trasmissioni a tutti i ricevitori in un ordine indefinito. Questa operazione viene chiamata trasmissione normale. Questo è più efficiente, ma significa che i ricevitori non possono leggere i risultati di altri ricevitori, propagare i dati ricevuti dalla trasmissione o interromperla.
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 oggetto Intent. 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 ulteriori informazioni all'intent con putExtra(String, Bundle). Puoi anche limitare una trasmissione a un insieme di app nella stessa organizzazione chiamando setPackage(String) nell'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 destinatario di una trasmissione.
Inviare trasmissioni con 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 destinatario 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 ricevente deve richiedere l'autorizzazione come segue:
<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 su autorizzazioni e sicurezza in
generale, consulta Autorizzazioni di sistema.
Ricevere trasmissioni con le autorizzazioni
Se specifichi un parametro di autorizzazione durante la registrazione di un broadcast receiver
(con
registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) o nel tag
<receiver> nel manifest), solo i broadcaster che hanno
richiesto l'autorizzazione con il tag <uses-permission> nel
manifest possono inviare un intent al ricevitore. Se l'autorizzazione è pericolosa,
deve essere concessa anche all'emittente.
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 la tua app ricevente 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
);
Quindi, 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" />
Evitare le trasmissioni all'interno dello stesso processo
Le trasmissioni sono progettate come meccanismo di comunicazione interprocesso (IPC) per l'invio di messaggi tra app diverse o tra il sistema e le app. L'invio di una trasmissione automatica, ovvero una trasmissione per la quale tutti i destinatari vengono eseguiti nello stesso processo che ha inviato la trasmissione, è molto inefficiente, crea un sovraccarico di sistema non necessario ed è fortemente sconsigliato.
Due scenari comuni in cui le app inviano trasmissioni a se stesse includono:
Comunicazione tra componenti nello stesso processo: ad esempio, passaggio di eventi o dati tra attività, frammenti, servizi o thread in background. Anziché inviare trasmissioni, utilizza meccanismi di comunicazione in-process standard come il pattern Observer o i flussi reattivi:
- Kotlin Flows (
SharedFloweStateFlow): una soluzione moderna e idiomatica in Kotlin per l'emissione e l'osservazione di flussi di eventi o aggiornamenti di stato tra coroutine e componenti dell'app. - Condiviso
ViewModel: facilita la condivisione di dati ed eventi tra diversi componenti dell'interfaccia utente (come frammenti o composable) all'interno della stessa attività. - Callback e listener: callback di interfacce standard o riferimenti a funzioni passati direttamente tra i componenti o registrati con un repository o un controller centrale.
- Kotlin Flows (
Gestione di eventi, job o sveglie di sistema: ad esempio, ricezione di un job programmato, una sveglia o un callback di sistema e poi invio di una trasmissione per attivare il lavoro effettivo. Anziché inviare una trasmissione, completa il lavoro direttamente all'interno del job (ad esempio un worker
JobServiceo WorkManager), un gestore di sveglie o un componente di callback di sistema oppure delega direttamente alle classi di logica di business della tua app.
Sui dispositivi con Android 17 QPR2 o versioni successive, il sistema trasmette le auto-trasmissioni in modo più efficiente restituendole al processo di invio, che le trasmette ai propri ricevitori sul thread principale. L'invio di un'intent di trasmissione automatica non aumenta l'importanza del processo e non impedisce il blocco di un processo memorizzato nella cache, quindi non fare affidamento sulle intent di trasmissione automatica per mantenere in esecuzione l'app o per eseguire operazioni in background. Anche con questa ottimizzazione, le trasmissioni automatiche sono meno efficienti dei meccanismi di comunicazione in-processo, quindi utilizza queste alternative.
Per ulteriori informazioni sulla progettazione della comunicazione tra i componenti dell'app, consulta la Guida all'architettura delle app.
Considerazioni sulla sicurezza
Ecco alcune considerazioni sulla sicurezza per l'invio e la ricezione di trasmissioni:
Se molte app sono registrate per ricevere la stessa trasmissione nel manifest, il sistema potrebbe avviare molte app, con un impatto notevole sulle prestazioni del dispositivo e sull'esperienza utente. Per evitare questo problema, preferisci l'utilizzo della registrazione del contesto alla dichiarazione del manifest. A volte, il sistema Android stesso impone l'utilizzo di ricevitori registrati nel contesto. Ad esempio, la trasmissione
CONNECTIVITY_ACTIONviene inviata solo ai 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 durante la registrazione di un broadcast receiver.
- Per i ricevitori dichiarati nel manifest, puoi impostare l'attributo android:exported su "false" nel manifest. Il destinatario non riceve trasmissioni da fonti 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 restituire rapidamente un valore. Se devi eseguire un lavoro di lunga durata, fai attenzione a generare thread o avviare servizi in background perché il sistema può terminare l'intero processo dopo la restituzione dionReceive(). Per saperne di più, consulta Effetto sullo stato del processo. Per eseguire operazioni a lunga esecuzione, ti consigliamo di:- Chiamando
goAsync()nel metodoonReceive()del destinatario e passandoBroadcastReceiver.PendingResulta un thread in background. In questo modo, la trasmissione rimane attiva dopo il ritorno daonReceive(). Tuttavia, anche con questo approccio, il sistema si aspetta che tu termini la trasmissione molto rapidamente (in meno di 10 secondi). Ti consente di spostare il lavoro in un altro thread per evitare problemi nel thread principale. - Pianificazione di un job con
JobScheduler. Per saperne di più, vedi Pianificazione intelligente dei job.
- Chiamando
Non avviare attività dai ricevitori di trasmissione perché l'esperienza utente è sgradevole, soprattutto se è presente più di un ricevitore. Valuta invece la possibilità di mostrare una notifica.