Les applications Android envoient et reçoivent des messages de diffusion à partir du système Android et d'autres applications Android, comme le modèle de conception publication/abonnement. Le système et les applications envoient généralement des diffusions lorsque certains événements se produisent. Par exemple, le système Android envoie des diffusions lorsque divers événements système se produisent, tels que le démarrage du système ou la recharge de l'appareil. Les applications envoient également des annonces personnalisées, par exemple pour avertir d'autres applications d'un élément susceptible de les intéresser (nouveau téléchargement de données, par exemple).
Les applications peuvent s'inscrire pour recevoir des diffusions spécifiques. Lorsqu'une annonce est envoyée, le système la redirige automatiquement vers les applications qui se sont abonnées pour recevoir ce type d'annonce.
En règle générale, les annonces peuvent être utilisées comme système de messagerie entre les applications et en dehors du parcours utilisateur normal. Toutefois, vous devez veiller à ne pas abuser de cette possibilité de répondre aux diffusions et d'exécuter des tâches en arrière-plan, ce qui peut ralentir les performances du système.
À propos des annonces du système
Le système envoie automatiquement des diffusions lorsque divers événements système se produisent, par exemple lorsque le système active ou désactive le mode Avion. Toutes les applications abonnées reçoivent ces diffusions.
L'objet Intent
encapsule le message de diffusion. La chaîne action
identifie l'événement qui s'est produit, par exemple android.intent.action.AIRPLANE_MODE
. L'intent peut également inclure des informations supplémentaires regroupées dans son champ supplémentaire.
Par exemple, l'intent Mode Avion inclut un élément booléen supplémentaire qui indique si le mode Avion est activé ou non.
Pour en savoir plus sur la lecture des intents et l'obtention de la chaîne d'action à partir d'un intent, consultez la section Intents et filtres d'intent.
Actions d'annonce du système
Pour obtenir la liste complète des actions de diffusion système, consultez le fichier BROADCAST_ACTIONS.TXT
du SDK Android. Chaque action de diffusion est associée à un champ constant. Par exemple, la valeur de la constante ACTION_AIRPLANE_MODE_CHANGED
est android.intent.action.AIRPLANE_MODE
.
La documentation de chaque action de diffusion est disponible dans son champ de constante associé.
Modifications apportées aux diffusions système
À mesure que la plate-forme Android évolue, elle modifie régulièrement le comportement des diffusions système. Tenez compte des modifications suivantes pour prendre en charge toutes les versions d'Android.
Android 14
Lorsque les applications sont à l'état mis en cache, le système optimise la diffusion des annonces pour assurer la santé du système. Par exemple, le système diffère les diffusions système moins importantes telles que ACTION_SCREEN_ON
lorsque l'application est dans un état mis en cache.
Une fois que l'application passe de l'état mis en cache à un cycle de vie de processus actif, le système diffuse toutes les diffusions différées.
Les diffusions importantes déclarées dans le fichier manifeste suppriment temporairement les applications de l'état mis en cache pour la diffusion.
Android 9
À partir d'Android 9 (niveau d'API 28), la diffusion NETWORK_STATE_CHANGED_ACTION
ne reçoit aucune information sur la position de l'utilisateur ni aucune donnée permettant de l'identifier personnellement.
Si votre application est installée sur un appareil équipé d'Android 9.0 (niveau d'API 28) ou version ultérieure, le système n'inclut pas les SSID, les BSSID, les informations de connexion ni les résultats de l'analyse dans les diffusions Wi-Fi. Pour obtenir ces informations, appelez plutôt getConnectionInfo()
.
Android 8.0
À partir d'Android 8.0 (niveau d'API 26), le système impose des restrictions supplémentaires sur les récepteurs déclarés dans le fichier manifeste.
Si votre application cible Android 8.0 ou version ultérieure, vous ne pouvez pas utiliser le fichier manifeste pour déclarer un récepteur pour la plupart des diffusions implicites (diffusions qui ne ciblent pas spécifiquement votre application). Vous pouvez toujours utiliser un récepteur enregistré par contexte lorsque l'utilisateur utilise activement votre application.
Android 7.0
Android 7.0 (niveau d'API 24) ou version ultérieure n'envoie pas les diffusions système suivantes:
De plus, les applications ciblant Android 7.0 et versions ultérieures doivent enregistrer la diffusion CONNECTIVITY_ACTION
à l'aide de registerReceiver(BroadcastReceiver, IntentFilter)
. Déclarer un récepteur dans le fichier manifeste ne fonctionne pas.
Recevoir des diffusions
Les applications peuvent recevoir des diffusions de deux manières: via des récepteurs enregistrés par le contexte et des récepteurs déclarés dans le fichier manifeste.
Récepteurs enregistrés en contexte
Les broadcast receivers enregistrés en contexte reçoivent des diffusions tant que leur contexte d'enregistrement est valide. Cela se produit généralement entre les appels à registerReceiver
et unregisterReceiver
. Le contexte d'enregistrement devient également non valide lorsque le système détruit le contexte correspondant. Par exemple, si vous vous inscrivez dans un contexte Activity
, vous recevez des diffusions tant que l'activité reste active. Si vous vous enregistrez avec le contexte d'application, vous recevez des diffusions tant que l'application s'exécute.
Pour enregistrer un récepteur avec un contexte, procédez comme suit:
Dans le fichier de compilation au niveau du module de votre application, incluez la version 1.9.0 ou ultérieure de la bibliothèque AndroidX Core:
Groovy
dependencies { def core_version = "1.15.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.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.15.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.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") }
Créez une instance de
BroadcastReceiver
:Kotlin
val myBroadcastReceiver = MyBroadcastReceiver()
Java
MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();
Créez une instance de
IntentFilter
:Kotlin
val filter = IntentFilter("com.example.snippets.ACTION_UPDATE_DATA")
Java
IntentFilter filter = new IntentFilter("com.example.snippets.ACTION_UPDATE_DATA");
Indiquez si le broadcast receiver doit être exporté et visible par les autres applications de l'appareil. Si ce broadcast receiver écoute les diffusions envoyées par le système ou par d'autres applications (même celles que vous possédez), utilisez l'indicateur
RECEIVER_EXPORTED
. Si ce récepteur n'écoute que les diffusions envoyées par votre application, utilisez l'indicateurRECEIVER_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;
Enregistrez le broadcast receiver en appelant
registerReceiver()
:Kotlin
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags)
Java
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags);
Pour ne plus recevoir de diffusions, appelez
unregisterReceiver(android.content.BroadcastReceiver)
. Veillez à désenregistrer le récepteur lorsque vous n'en avez plus besoin ou que le contexte n'est plus valide.
Désenregistrer votre broadcast receiver
Lorsque le broadcast receiver est enregistré, il contient une référence au contexte avec lequel vous l'avez enregistré. Cela peut potentiellement entraîner des fuites si la portée enregistrée du récepteur dépasse la portée du cycle de vie du contexte. Par exemple, cela peut se produire lorsque vous enregistrez un récepteur sur un champ d'application, mais que vous oubliez de l'annuler lorsque le système détruit l'activité. Par conséquent, désinscrivez toujours votre 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
}
}
Enregistrer les récepteurs dans le champ d'application le plus limité
Votre broadcast receiver ne doit être enregistré que lorsque vous êtes réellement intéressé par le résultat. Choisissez le champ d'application du récepteur le plus petit possible:
- Méthodes de cycle de vie
LifecycleResumeEffect
ouonResume
/onPause
de l'activité: le broadcast receiver ne reçoit des mises à jour que lorsque l'application est dans son état de reprise. - Méthodes de cycle de vie
LifecycleStartEffect
ouonStart
/onStop
de l'activité: le broadcast receiver ne reçoit des mises à jour que lorsque l'application est dans son état de reprise. DisposableEffect
: le broadcast receiver ne reçoit des mises à jour que lorsque le composable se trouve dans l'arborescence de composition. Ce champ d'application n'est pas associé au champ d'application du cycle de vie de l'activité. Envisagez d'enregistrer le récepteur sur le contexte de l'application. En effet, le composable pourrait théoriquement survivre à la portée du cycle de vie de l'activité et fuir l'activité.- Activité
onCreate
/onDestroy
: le broadcast receiver reçoit des mises à jour lorsque l'activité est dans son état créé. Veillez à vous désinscrire dansonDestroy()
et non dansonSaveInstanceState(Bundle)
, car il est possible que cette méthode ne soit pas appelée. - Portée personnalisée: par exemple, vous pouvez enregistrer un récepteur dans votre portée
ViewModel
afin qu'il survive à la recréation de l'activité. Assurez-vous d'utiliser le contexte de l'application pour enregistrer le récepteur, car il peut survivre au champ d'application du cycle de vie de l'activité et fuir l'activité.
Créer un composable avec état et sans état
Compose propose des composables avec et sans état. L'enregistrement ou le désenregistrement d'un broadcast receiver dans un composable le rend doté d'un état. Le composable n'est pas une fonction déterministe qui affiche le même contenu lorsque les mêmes paramètres lui sont transmis. L'état interne peut changer en fonction des appels au broadcast receiver enregistré.
Dans Compose, nous vous recommandons de diviser vos composables en versions avec état et sans état. Par conséquent, nous vous recommandons de hisser la création du broadcast receiver à partir d'un composable pour le rendre sans état:
@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
}
Récepteurs déclarés dans le fichier manifeste
Si vous déclarez un broadcast receiver dans votre fichier manifeste, le système lance votre application lorsque l'annonce est envoyée. Si l'application n'est pas déjà en cours d'exécution, le système la lance.
Pour déclarer un broadcast receiver dans le fichier manifeste, procédez comme suit:
Spécifiez l'élément
<receiver>
dans le fichier manifeste de votre application.<!-- 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>
Les filtres d'intent spécifient les actions de diffusion auxquelles votre broadcast receiver s'abonne.
Sous-classe
BroadcastReceiver
et implémentation deonReceive(Context, Intent)
. Le broadcast receiver de l'exemple suivant consigne et affiche le contenu de la diffusion: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); } } } }
Le gestionnaire de paquets du système enregistre le récepteur lorsque l'application est installée. Le récepteur devient alors un point d'entrée distinct dans votre application, ce qui signifie que le système peut démarrer l'application et diffuser la diffusion si l'application n'est pas en cours d'exécution.
Le système crée un objet de composant BroadcastReceiver
pour gérer chaque diffusion qu'il reçoit. Cet objet n'est valide que pendant la durée de l'appel à onReceive(Context, Intent)
. Une fois que votre code est renvoyé à partir de cette méthode, le système considère que le composant n'est plus actif.
Effets sur l'état du processus
Le fait que votre BroadcastReceiver
fonctionne ou non affecte le processus qu'il contient, ce qui peut modifier la probabilité de plantage du système. Un processus au premier plan exécute la méthode onReceive()
d'un récepteur. Le système exécute le processus, sauf en cas de pression de mémoire extrême.
Le système désactive le BroadcastReceiver
après onReceive()
.
L'importance du processus hôte du destinataire dépend des composants de son application. Si ce processus n'héberge qu'un seul broadcast receiver déclaré dans le fichier manifeste, le système peut le fermer après onReceive()
pour libérer des ressources pour d'autres processus plus critiques. Cela est courant pour les applications avec lesquelles l'utilisateur n'a jamais interagi ou avec lesquelles il n'a pas interagi récemment.
Par conséquent, les broadcast receivers ne doivent pas lancer de threads en arrière-plan de longue durée.
Le système peut arrêter le processus à tout moment après onReceive()
pour récupérer de la mémoire, ce qui met fin au thread créé. Pour maintenir le processus actif, planifiez un JobService
à partir du récepteur à l'aide de JobScheduler
afin que le système sache que le processus fonctionne toujours. Pour en savoir plus, consultez la section Présentation des tâches en arrière-plan.
Envoyer des annonces
Android propose aux applications deux méthodes d'envoi de diffusions:
- La méthode
sendOrderedBroadcast(Intent, String)
envoie des annonces à un seul destinataire à la fois. Chaque destinataire peut propager un résultat au destinataire suivant. Il peut également interrompre complètement la diffusion afin qu'elle n'atteigne pas d'autres récepteurs. Vous pouvez contrôler l'ordre d'exécution des broadcast receivers. Pour ce faire, utilisez l'attribut android:priority du filtre d'intent correspondant. Les récepteurs ayant la même priorité sont exécutés dans un ordre arbitraire. - La méthode
sendBroadcast(Intent)
envoie des diffusions à tous les récepteurs dans un ordre indéfini. C'est ce qu'on appelle une diffusion normale. Cette méthode est plus efficace, mais signifie que les destinataires ne peuvent pas lire les résultats d'autres destinataires, propager les données reçues de la diffusion ni interrompre la diffusion.
L'extrait de code suivant montre comment envoyer une diffusion en créant un intent et en appelant 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);
Le message de diffusion est encapsulé dans un objet Intent
. La chaîne action
de l'intent doit fournir la syntaxe du nom de package Java de l'application et identifier de manière unique l'événement de diffusion. Vous pouvez joindre des informations supplémentaires à l'intent avec putExtra(String, Bundle)
. Vous pouvez également limiter une diffusion à un ensemble d'applications de la même organisation en appelant setPackage(String)
sur l'intent.
Limiter les diffusions avec des autorisations
Les autorisations vous permettent de limiter les diffusions à l'ensemble d'applications disposant de certaines autorisations. Vous pouvez appliquer des restrictions à l'expéditeur ou au destinataire d'une diffusion.
Envoyer des annonces avec des autorisations
Lorsque vous appelez sendBroadcast(Intent, String)
ou sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String,
Bundle)
, vous pouvez spécifier un paramètre d'autorisation. Seuls les récepteurs qui ont demandé cette autorisation avec la balise <uses-permission>
dans leur fichier manifeste peuvent recevoir l'annonce. Si l'autorisation est dangereuse, vous devez l'accorder avant que le récepteur puisse recevoir la diffusion. Par exemple, le code suivant envoie une diffusion avec une autorisation:
Kotlin
context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION)
Java
context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION);
Pour recevoir la diffusion, l'application réceptrice doit demander l'autorisation comme suit:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Vous pouvez spécifier une autorisation système existante telle que BLUETOOTH_CONNECT
ou définir une autorisation personnalisée avec l'élément <permission>
. Pour en savoir plus sur les autorisations et la sécurité en général, consultez la section Autorisations système.
Recevoir des diffusions avec des autorisations
Si vous spécifiez un paramètre d'autorisation lors de l'enregistrement d'un broadcast receiver (avec registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
ou dans la balise <receiver>
de votre fichier manifeste), seuls les diffuseurs qui ont demandé l'autorisation avec la balise <uses-permission>
dans leur fichier manifeste peuvent envoyer un intent au broadcast receiver. Si l'autorisation est dangereuse, elle doit également être accordée au diffuseur.
Par exemple, supposons que votre application réceptrice dispose d'un récepteur déclaré dans le fichier manifeste comme suit:
<!-- 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>
Ou votre application réceptrice dispose d'un broadcast receiver enregistré en contexte comme suit:
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
);
Ensuite, pour pouvoir envoyer des diffusions à ces récepteurs, l'application d'envoi doit demander l'autorisation comme suit:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Points à noter concernant la sécurité
Voici quelques considérations de sécurité concernant l'envoi et la réception de diffusions:
Si de nombreuses applications se sont enregistrées pour recevoir le même broadcast dans leur fichier manifeste, le système peut lancer de nombreuses applications, ce qui a un impact important sur les performances de l'appareil et sur l'expérience utilisateur. Pour éviter cela, privilégiez l'enregistrement de contexte à la déclaration de fichier manifeste. Parfois, le système Android lui-même applique l'utilisation de récepteurs enregistrés par contexte. Par exemple, la diffusion
CONNECTIVITY_ACTION
n'est envoyée qu'aux récepteurs enregistrés par contexte.Ne diffusez pas d'informations sensibles à l'aide d'un intent implicite. Toute application peut lire les informations si elle s'inscrit pour recevoir la diffusion. Vous pouvez contrôler qui peut recevoir vos diffusions de trois manières:
- Vous pouvez spécifier une autorisation lorsque vous envoyez une diffusion.
- Sous Android 4.0 (niveau d'API 14) ou version ultérieure, vous pouvez spécifier un package avec
setPackage(String)
lorsque vous envoyez une annonce. Le système limite la diffusion à l'ensemble d'applications correspondant au package.
Lorsque vous enregistrez un récepteur, n'importe quelle application peut envoyer des annonces potentiellement malveillantes au récepteur de votre application. Il existe plusieurs façons de limiter les diffusions que votre application reçoit:
- Vous pouvez spécifier une autorisation lorsque vous enregistrez un broadcast receiver.
- Pour les récepteurs déclarés dans le fichier manifeste, vous pouvez définir l'attribut android:exported sur "false" dans le fichier manifeste. Le récepteur ne reçoit pas de diffusions provenant de sources extérieures à l'application.
L'espace de noms des actions de diffusion est global. Assurez-vous que les noms d'action et les autres chaînes sont écrits dans un espace de noms dont vous êtes propriétaire. Sinon, vous risquez d'entrer en conflit par inadvertance avec d'autres applications.
Étant donné que la méthode
onReceive(Context, Intent)
d'un récepteur s'exécute sur le thread principal, elle doit s'exécuter et renvoyer rapidement. Si vous devez effectuer une tâche de longue durée, veillez à ne pas créer de threads ni à démarrer de services en arrière-plan, car le système peut arrêter l'ensemble du processus après le retour deonReceive()
. Pour en savoir plus, consultez la section Effet sur l'état du processus. Pour effectuer une tâche de longue durée, nous vous recommandons les points suivants:- Appeler
goAsync()
dans la méthodeonReceive()
de votre récepteur et transmettre leBroadcastReceiver.PendingResult
à un thread en arrière-plan. Cela permet de maintenir la diffusion active après le retour deonReceive()
. Toutefois, même avec cette approche, le système s'attend à ce que vous terminiez la diffusion très rapidement (en moins de 10 secondes). Il vous permet de déplacer des tâches vers un autre thread pour éviter de perturber le thread principal. - Planifier une tâche avec
JobScheduler
Pour en savoir plus, consultez la section Planification intelligente des tâches.
- Appeler
Ne démarrez pas d'activités à partir de broadcast receivers, car l'expérience utilisateur est désagréable, en particulier s'il y a plusieurs récepteurs. Nous vous conseillons plutôt d'afficher une notification.