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 pubblico/abbonamento. 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 inoltra automaticamente alle app che si sono iscritte per ricevere quel determinato tipo di trasmissione.
In generale, le trasmissioni possono essere utilizzate come sistema di messaggistica tra 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 il sistema.
Informazioni sulle trasmissioni di sistema
Il sistema invia automaticamente le trasmissioni quando si verificano vari eventi di sistema, ad esempio quando attiva e disattiva la modalità aereo. Tutte le app a cui hai effettuato l'iscrizione ricevono queste trasmissioni.
L'oggetto Intent
inserisce un a capo nel messaggio di trasmissione. 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 Modalità aereo include un extra booleano che indica se la modalità aereo è attiva o meno.
Per ulteriori informazioni su come leggere gli intent e ottenere la stringa di azione da un intento, consulta Intent e filtri intent.
Azioni di trasmissione di sistema
Per un elenco completo delle azioni di trasmissione di sistema, consulta il BROADCAST_ACTIONS.TXT
file 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 di ogni azione di trasmissione è disponibile nel relativo campo costante associato.
Modifiche alle trasmissioni di sistema
Con l'evoluzione della piattaforma Android, il comportamento delle trasmissioni di sistema cambia periodicamente. Tieni presente le seguenti modifiche per supportare tutte le versioni di Android.
Android 14
Quando le app sono in stato memorizzato nella cache, il sistema ottimizza la trasmissione per l'integrità del sistema. Ad esempio, il sistema rimanda le trasmissioni di sistema meno importanti come ACTION_SCREEN_ON
mentre l'app è in uno stato memorizzato nella cache.
Quando l'app passa dallo stato memorizzato nella cache a un ciclo di vita del processo attivo, il sistema invia eventuali trasmissioni differite.
Le trasmissioni importanti dichiarate nel manifest rimuovono temporaneamente le app dallo stato memorizzato nella cache per il caricamento.
Android 9
A partire da Android 9 (livello API 28), la trasmissione NETWORK_STATE_CHANGED_ACTION
non riceve informazioni sulla posizione dell'utente o su dati che consentono di identificarlo personalmente.
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 di connessione o risultati di scansione nelle trasmissioni Wi-Fi. Per ricevere queste informazioni, chiama
getConnectionInfo()
.
Android 8.0
A partire da Android 8.0 (livello API 26), il sistema impone ulteriori limitazioni ai destinatari dichiarati nel file manifest.
Se la tua app ha come target Android 8.0 o versioni successive, non puoi utilizzare il file manifest per dichiarare un receiver per la maggior parte delle trasmissioni implicite (trasmissioni che non hanno come target specifico la tua app). Puoi comunque utilizzare un ricevitore registrato in base al 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 le trasmissioni in due modi: tramite i receiver registrati in base al contesto e i receiver dichiarati nel file manifest.
Ricevitori registrati in base al contesto
I receiver registrati in base al contesto ricevono le trasmissioni purché il loro
contesto di registrazione sia valido. In genere, si tratta del periodo compreso 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 broadcasting per tutto il tempo di esecuzione dell'app.
Per registrare un destinatario con un contesto:
Nel file di compilazione a livello di modulo dell'app, includi la versione 1.9.0 o successive della libreria AndroidX Core:
Alla moda
dependencies { def core_version = "1.13.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.0.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-alpha02" }
Kotlin
dependencies { val core_version = "1.13.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.0.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-alpha02") }
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 ricevitore di trasmissione deve essere esportato e visibile alle altre app sul dispositivo. Se questo ricevitore è in ascolto per le trasmissioni inviate dal sistema o da altre app, anche di tua proprietà, utilizza il flag
RECEIVER_EXPORTED
. Se invece questo ricevitore è in ascolto solo per le 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 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 eseguire la registrazione del ricevitore quando non ti serve più o quando il contesto non è più valido.
Annullare la registrazione del broadcast receiver
Quando il ricevitore di trasmissione è registrato, contiene un riferimento al contesto con cui lo hai 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ò accadere quando registri un destinatario in un ambito Attività, ma dimentichi di annullarne la registrazione quando il sistema distrugge l'attività. Pertanto, sempre annulla 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ù ristretto
Il ricevitore di trasmissione deve essere registrato solo quando ti interessa effettivamente il risultato. Scegli l'ambito del destinatario più piccolo possibile:
- Metodi di ciclo di vita
LifecycleResumeEffect
o attivitàonResume
/onPause
: il ricevitore di trasmissione riceve aggiornamenti solo quando l'app è in stato di ripresa. - Metodi di ciclo di vita
LifecycleStartEffect
o attivitàonStart
/onStop
: il ricevitore di trasmissione riceve aggiornamenti solo quando l'app è in stato di ripresa. DisposableEffect
: il broadcast receiver riceve aggiornamenti solo quando il composable è nell'albero di composizione. Questo ambito non è associato 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 dell'attività.- Attività
onCreate
/onDestroy
: il ricevitore di trasmissione riceve aggiornamenti mentre l'attività è nello stato di creazione. Assicurati di annullare la registrazione inonDestroy()
e non inonSaveInstanceState(Bundle)
perché quest'ultima potrebbe non essere chiamata. - Un ambito personalizzato: ad esempio, puoi registrare un destinatario nel tuo ambito
ViewModel
in modo che sopravviva alla ricreazione dell'attività. Assicurati di utilizzare il contesto dell'applicazione per registrare il destinatario, in quanto il destinatario può sopravvivere all'ambito del ciclo di vita dell'attività e causare una fuga di dati dell'attività.
Crea composibili stateful e stateless
Compose ha composable stateful e stateless. La registrazione o la disattivazione di un 'entità BroadcastReceiver all'interno di un composable lo rende stateful. Il composable non è una funzione deterministica che restituisce gli stessi contenuti 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 suddividere i composabili in versioni con stato e senza stato. Pertanto, ti consigliamo di eseguire la riavvolgimento della creazione del ricevitore di trasmissione da un Composable per renderlo senza stato:
@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'entità di ricezione di trasmissione nel manifest, il sistema avvia la tua app quando viene inviata la trasmissione. Se l'app non è già in esecuzione, il sistema la avvia.
Per dichiarare un ricevitore di trasmissione nel manifest, svolgi i seguenti passaggi:
Specifica l'elemento
<receiver>
nel file 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 per intent specificano le azioni di trasmissione a cui si iscrive il tuo ricevitore.
Sottoclasse
BroadcastReceiver
e implementaonReceive(Context, Intent)
. Il ricevitore di trasmissione nell'esempio riportato di seguito 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 dei pacchetti di sistema registra il ricevitore quando viene installata l'app. Il ricevitore diventa quindi un punto di contatto separato per la tua app, il che significa che il sistema può avviare l'app e trasmettere 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 ritorna da questo metodo, il sistema considera il componente non più attivo.
Effetti sullo stato del processo
Il fatto che BroadcastReceiver
sia in funzione o meno influisce sul processo contenuto, che può alterare la probabilità di arresto anomalo 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 il BroadcastReceiver
dopo onReceive()
.
Il significato del processo dell'attività del destinatario dipende dai componenti dell'app. Se il processo ospita solo un ricevitore dichiarato nel manifest, il sistema potrebbe interromperlo dopo onReceive()
per liberare risorse per altri processi più critici. Questo accade spesso per le app con cui l'utente non ha mai interagito o con cui non ha interagito di recente.
Pertanto, i broadcast receiver non devono avviare thread in background di lunga durata.
Il sistema può interrompere il processo in qualsiasi momento dopo onReceive()
per recuperare la 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 funzione. La Panoramica del lavoro in background fornisce ulteriori dettagli.
Inviare annunci
Android offre due modi per consentire alle app di inviare trasmissioni:
- Il metodo
sendOrderedBroadcast(Intent, String)
invia le trasmissioni a un solo ricevitore alla volta. Man mano che ogni destinatario viene eseguito a turno, può propagare un risultato al successivo. Può anche interrompere completamente la trasmissione in modo che non raggiunga altri ricevitori. Puoi controllare l'ordine di esecuzione dei ricevitori. A tale scopo, utilizza l'attributo android:priority del filtro intent corrispondente. I destinatari con la stessa priorità vengono eseguiti in un ordine arbitrario. - Il metodo
sendBroadcast(Intent)
invia le trasmissioni a tutti i destinatari in un ordine indefinito. Questa è una 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 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);
Il messaggio di trasmissione è 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 ricevente possa ricevere la trasmissione. Ad esempio, il seguente codice invia un broadcast 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 destinazione deve richiedere l'autorizzazione come segue:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Puoi specificare un'autorizzazione di sistema esistente come
BLUETOOTH_CONNECT
o definire un'autorizzazione personalizzata con l'elemento
<permission>
. Per informazioni sulle autorizzazioni e sulla sicurezza in generale, vedi Autorizzazioni di sistema.
Ricevere trasmissioni con autorizzazioni
Se specifichi un parametro di autorizzazione durante la registrazione di un'entità di ricezione di trasmissione
(con
registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
o nel
<receiver>
tag nel tuo
manifest), solo i trasmettitori che hanno
richiesto l'autorizzazione con il tag <uses-permission>
nel loro
manifest possono inviare un Intent all'entità di ricezione. 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>
In alternativa, l'app di ricezione ha un receiver registrato in base al 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
);
Poi, per poter inviare le 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
Ecco alcune considerazioni sulla sicurezza per l'invio e la ricezione delle trasmissioni:
Se molte app si sono registrate per ricevere la stessa trasmissione nel loro manifest, il sistema potrebbe avviare molte app, con un impatto sostanziale sia sulle prestazioni del dispositivo sia sull'esperienza utente. Per evitare questo problema, preferisci utilizzare la registrazione del contesto rispetto alla dichiarazione manifest. A volte, il sistema Android stesso impone l'utilizzo di ricevitori registrati in base al contesto. Ad esempio, la trasmissione
CONNECTIVITY_ACTION
viene inviata solo ai transceiver registrati in base al contesto.Non trasmettere informazioni sensibili utilizzando un'intenzione implicita. 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 corrispondenti al pacchetto.
Quando registri un ricevitore, qualsiasi app può inviare al ricevitore della tua app trasmissioni potenzialmente dannose. Esistono diversi modi per limitare le trasmissioni ricevute dalla tua app:
- Puoi specificare un'autorizzazione quando registri un'entità BroadcastReceiver.
- Per i receiver dichiarati nel file manifest, puoi impostare l'attributo android:exported su "false" nel file manifest. Il ricevitore non riceve le 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 scritti in uno spazio dei nomi di tua proprietà. In caso contrario, potresti inadvertently entrare in conflitto con altre app.
Poiché il metodo
onReceive(Context, Intent)
di un ricevente viene eseguito nel thread principale, dovrebbe eseguire e restituire rapidamente. Se devi eseguire operazioni a lungo termine, fai attenzione a generare thread o avviare servizi in background perché il sistema può interrompere l'intero processo dopo il ritorno dionReceive()
. Per ulteriori informazioni, consulta Effetto sullo stato del processo. Per eseguire attività che richiedono molto tempo, consigliamo di:- Chiama
goAsync()
nel metodoonReceive()
del ricevitore e trasmettiBroadcastReceiver.PendingResult
a 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 completi la trasmissione molto rapidamente (in meno di 10 secondi). Tuttavia, consente di spostare il lavoro in un altro thread per evitare glitch nel thread principale. - Pianificazione di un job con
JobScheduler
. Per ulteriori informazioni, consulta Pianificazione dei job intelligente.
- Chiama
Non avviare attività dai ricevitori di trasmissione perché l'esperienza utente è spiacevole, soprattutto se sono presenti più ricevitori. In alternativa, valuta la possibilità di mostrare una notifica.