Android-Apps senden und empfangen Broadcast-Nachrichten vom Android-System und von anderen Android-Apps. Das ähnelt dem Publish-Subscribe Designmuster. Das System und die Apps senden in der Regel Broadcasts, wenn bestimmte Ereignisse eintreten. Das Android-System sendet beispielsweise Broadcasts, wenn verschiedene Systemereignisse auftreten, z. B. beim Systemstart oder beim Aufladen des Geräts. Apps senden auch benutzerdefinierte Broadcasts, um beispielsweise andere Apps über etwas zu informieren, das für sie von Interesse sein könnte (z. B. ein neuer Download von Daten).
Apps können sich registrieren, um bestimmte Broadcasts zu empfangen. Wenn ein Broadcast gesendet wird, leitet das System ihn automatisch an Apps weiter, die ihn abonniert haben.
Im Allgemeinen können Broadcasts als Messaging-System für Apps und außerhalb des normalen Nutzerablaufs verwendet werden. Sie müssen jedoch darauf achten, die Möglichkeit, auf Broadcasts zu antworten und Jobs im Hintergrund auszuführen, nicht zu missbrauchen, da dies die Systemleistung beeinträchtigen kann.
System-Broadcasts
Das System sendet automatisch Broadcasts, wenn verschiedene Systemereignisse auftreten, z. B. wenn das System in den Flugmodus wechselt oder ihn verlässt. Alle abonnierten Apps erhalten diese Broadcasts.
Das Intent-Objekt umschließt die Nachricht an alle. Der String action gibt
das aufgetretene Ereignis an, z. B. android.intent.action.AIRPLANE_MODE. Der Intent kann auch zusätzliche Informationen enthalten, die im Feld „extra“ gebündelt sind.
Der Intent für den Flugmodus enthält beispielsweise ein boolesches Extra, das angibt, ob der Flugmodus aktiviert ist.
Weitere Informationen zum Lesen von Intents und zum Abrufen des Aktionsstrings aus einem Intent finden Sie unter Intents und Intent-Filter.
System-Broadcast-Aktionen
Eine vollständige Liste der System-Broadcast-Aktionen finden Sie in der Datei BROADCAST_ACTIONS.TXT im Android SDK. Jeder Broadcast-Aktion ist ein Konstantenfeld zugeordnet. Der Wert der Konstanten
ACTION_AIRPLANE_MODE_CHANGED ist beispielsweise android.intent.action.AIRPLANE_MODE.
Die Dokumentation für jede Broadcast-Aktion ist im zugehörigen Konstantenfeld verfügbar.
Änderungen an System-Broadcasts
Im Laufe der Entwicklung der Android-Plattform ändert sich regelmäßig das Verhalten von System-Broadcasts. Beachten Sie die folgenden Änderungen, um alle Android-Versionen zu unterstützen.
Android 16
In Android 16 kann die Reihenfolge der Broadcast-Zustellung mit dem android:priority
Attribut oder IntentFilter.setPriority() über verschiedene Prozesse hinweg
nicht garantiert werden. Broadcast-Prioritäten werden nur innerhalb desselben Anwendungsprozesses berücksichtigt, nicht über alle Prozesse hinweg.
Außerdem sind Broadcast-Prioritäten automatisch auf den Bereich
(SYSTEM_LOW_PRIORITY + 1, SYSTEM_HIGH_PRIORITY - 1) beschränkt.
Nur Systemkomponenten dürfen SYSTEM_LOW_PRIORITY und SYSTEM_HIGH_PRIORITY als Broadcast-Priorität festlegen.
Android 14
Wenn sich Apps im Cache befinden, optimiert das System die Broadcast-Zustellung
um die Systemleistung aufrechtzuerhalten. Das System verschiebt beispielsweise weniger wichtige System
Broadcasts wie ACTION_SCREEN_ON, während sich die App im Cache befindet.
Sobald die App aus dem Cache in einen aktiven Prozesslebenszyklus,
liefert das System alle verschobenen Broadcasts aus.
Wichtige Broadcasts, die im Manifest deklariert sind, entfernen Apps vorübergehend aus dem Cache, damit sie zugestellt werden können.
Android 9
Ab Android 9 (API-Level 28) enthält der NETWORK_STATE_CHANGED_ACTION
Broadcast keine Informationen zum Standort des Nutzers oder zu personenbezogenen
Daten.
Wenn Ihre App auf einem Gerät mit Android 9.0 (API-Level 28) oder höher installiert ist, enthält das System keine SSIDs, BSSIDs, Verbindungsinformationen oder Scanergebnisse in WLAN-Broadcasts. Rufen Sie stattdessen
getConnectionInfo() auf, um diese Informationen zu erhalten.
Android 8.0
Ab Android 8.0 (API-Level 26) gelten für im Manifest deklarierte Empfänger zusätzliche Einschränkungen.
Wenn Ihre App auf Android 8.0 oder höher ausgerichtet ist, können Sie im Manifest keinen Empfänger für die meisten impliziten Broadcasts deklarieren (Broadcasts, die nicht speziell auf Ihre App ausgerichtet sind). Sie können weiterhin einen kontextregistrierten Empfänger verwenden, wenn der Nutzer Ihre App aktiv verwendet.
Android 7.0
Unter Android 7.0 (API-Level 24) und höher werden die folgenden System-Broadcasts nicht gesendet:
Außerdem müssen Apps, die auf Android 7.0 und höher ausgerichtet sind, den
CONNECTIVITY_ACTION Broadcast mit
registerReceiver(BroadcastReceiver, IntentFilter) registrieren. Die Deklaration eines Empfängers im Manifest funktioniert nicht.
Broadcasts empfangen
Apps können Broadcasts auf zwei Arten empfangen: über kontextregistrierte Empfänger und im Manifest deklarierte Empfänger.
Kontextregistrierte Empfänger
Kontextregistrierte Empfänger empfangen Broadcasts, solange ihr Registrierungskontext gültig ist. Das ist in der Regel zwischen den Aufrufen von registerReceiver und
unregisterReceiver. Der Registrierungskontext wird auch ungültig, wenn das System den entsprechenden Kontext zerstört. Wenn Sie sich beispielsweise in einem
Activity-Kontext registrieren, empfangen Sie Broadcasts, solange die Aktivität
aktiv bleibt. Wenn Sie sich mit dem Anwendungskontext registrieren, empfangen Sie Broadcasts, solange die App ausgeführt wird.
So registrieren Sie einen Empfänger mit einem Kontext:
Fügen Sie in der Build-Datei auf Modulebene Ihrer App Version 1.9.0 oder höher von der AndroidX Core-Bibliothek ein:
Groovy
dependencies { def core_version = "1.19.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.19.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") }
Erstellen Sie eine Instanz von
BroadcastReceiver:Kotlin
val myBroadcastReceiver = MyBroadcastReceiver()Java
MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();Erstellen Sie eine Instanz von
IntentFilter:Kotlin
val filter = IntentFilter("com.example.snippets.ACTION_UPDATE_DATA")Java
IntentFilter filter = new IntentFilter("com.example.snippets.ACTION_UPDATE_DATA");Wählen Sie aus, ob der Übertragungsempfänger exportiert und für andere Apps auf dem Gerät sichtbar sein soll. Wenn dieser Empfänger auf Broadcasts wartet, die vom System oder von anderen Apps gesendet werden – auch von anderen Apps, die Ihnen gehören –, verwenden Sie das Flag
RECEIVER_EXPORTED. Wenn dieser Empfänger stattdessen nur auf Broadcasts wartet, die von Ihrer App gesendet werden, verwenden Sie das 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;Registrieren Sie den Empfänger mit
registerReceiver():Kotlin
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags)Java
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags);Rufen Sie
unregisterReceiver(android.content.BroadcastReceiver)auf, um keine Broadcasts mehr zu empfangen. Heben Sie die Registrierung des Empfängers auf, wenn Sie ihn nicht mehr benötigen oder der Kontext nicht mehr gültig ist.
Registrierung des Übertragungsempfängers aufheben
Solange der Übertragungsempfänger registriert ist, enthält er einen Verweis auf den Kontext, mit dem Sie ihn registriert haben. Dies kann zu Speicherlecks führen, wenn der registrierte Bereich des Empfängers den Lebenszyklusbereich des Kontexts überschreitet. Das kann beispielsweise passieren, wenn Sie einen Empfänger in einem Aktivitätsbereich registrieren, aber vergessen, die Registrierung aufzuheben, wenn das System die Aktivität zerstört. Heben Sie daher immer die Registrierung Ihres Übertragungsempfängers auf.
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
}
}
Empfänger im kleinstmöglichen Bereich registrieren
Ihr Übertragungsempfänger sollte nur registriert werden, wenn Sie tatsächlich an dem Ergebnis interessiert sind. Wählen Sie den kleinstmöglichen Empfängerbereich aus:
LifecycleResumeEffectoder AktivitätslebenszyklusmethodenonResume/onPause: Der Übertragungsempfänger erhält nur Updates, wenn sich die App im fortgesetzten Zustand befindet.LifecycleStartEffectoder AktivitätslebenszyklusmethodenonStart/onStop: Der Übertragungsempfänger erhält nur Updates, wenn sich die App im fortgesetzten Zustand befindet.DisposableEffect: Der Übertragungsempfänger erhält nur Updates, wenn sich die zusammensetzbare Funktion im Kompositionsbaum befindet. Dieser Bereich ist nicht an den Aktivitätslebenszyklusbereich angehängt. Registrieren Sie den Empfänger im Anwendungskontext. Das liegt daran, dass die zusammensetzbare Funktion theoretisch den Aktivitätslebenszyklus überdauern und die Aktivität lecken kann.- Aktivität
onCreate/onDestroy: Der Übertragungsempfänger erhält Updates, wenn sich die Aktivität im erstellten Zustand befindet. Heben Sie die Registrierung inonDestroy()und nicht inonSaveInstanceState(Bundle)auf, da diese möglicherweise nicht aufgerufen wird. - Ein benutzerdefinierter Bereich: Sie können beispielsweise einen Empfänger im Bereich
ViewModelregistrieren, damit er die Neuerstellung der Aktivität überdauert. Verwenden Sie den Anwendungskontext, um den Empfänger zu registrieren, da der Empfänger den Lebenszyklusbereich der Aktivität überdauern und die Aktivität lecken kann.
Zustandsorientierte und zustandslose zusammensetzbare Funktionen erstellen
Compose hat zustandsorientierte und zustandslose zusammensetzbare Funktionen. Wenn Sie einen Übertragungsempfänger innerhalb einer zusammensetzbaren Funktion registrieren oder die Registrierung aufheben, wird er zustandsorientiert. Die zusammensetzbare Funktion ist keine deterministische Funktion, die bei Übergabe derselben Parameter denselben Inhalt rendert. Der interne Zustand kann sich je nach Aufrufen des registrierten Broadcast-Empfängers ändern.
Als Best Practice in Compose empfehlen wir, Ihre zusammensetzbaren Funktionen in zustandsorientierte und zustandslose Versionen aufzuteilen. Daher empfehlen wir, die Erstellung des Übertragungsempfängers aus einer komponierbaren Funktion herauszuheben, um ihn zustandslos zu machen:
@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
}
Im Manifest deklarierte Empfänger
Wenn Sie einen Übertragungsempfänger im Manifest deklarieren, startet das System Ihre App, wenn der Broadcast gesendet wird. Wenn die App noch nicht ausgeführt wird, startet das System sie.
So deklarieren Sie einen Übertragungsempfänger im Manifest:
Geben Sie das
<receiver>Element im Manifest Ihrer App an.<!-- 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>Die Intent-Filter geben die Broadcast-Aktionen an, die Ihr Empfänger abonniert.
Erstellen Sie eine Unterklasse von
BroadcastReceiverund implementieren SieonReceive(Context, Intent). Der Übertragungsempfänger im folgenden Beispiel protokolliert und zeigt den Inhalt des Broadcasts an: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); } } } }
Der System-Paketmanager registriert den Empfänger, wenn die App installiert wird. Der Empfänger wird dann zu einem separaten Einstiegspunkt in Ihre App. Das bedeutet, dass das System die App starten und den Broadcast zustellen kann, wenn die App nicht ausgeführt wird.
Das System erstellt ein neues BroadcastReceiver-Komponentenobjekt, um
jeden empfangenen Broadcast zu verarbeiten. Dieses Objekt ist nur für die Dauer von
dem Aufruf von onReceive(Context, Intent) gültig. Sobald Ihr Code von dieser Methode zurückkehrt, betrachtet das System die Komponente als nicht mehr aktiv.
Auswirkungen auf den Prozessstatus
Ob Ihr BroadcastReceiver ausgeführt wird oder nicht, wirkt sich auf den enthaltenen
Prozess aus, was die Wahrscheinlichkeit beeinflussen kann, dass er vom System beendet wird. Ein Vordergrundprozess
führt die Methode onReceive() eines Empfängers aus. Das System führt den Prozess aus, es sei denn, der Arbeitsspeicher ist extrem ausgelastet.
Das System deaktiviert den BroadcastReceiver nach onReceive().
Die Bedeutung des Hostprozesses des Empfängers hängt von seinen App-Komponenten ab. Wenn dieser Prozess nur einen im Manifest deklarierten Empfänger hostet, beendet das System ihn möglicherweise nach onReceive(), um Ressourcen für andere, wichtigere Prozesse freizugeben. Das ist häufig bei Apps der Fall, mit denen der Nutzer noch nie oder seit Kurzem nicht mehr interagiert hat.
Daher sollten Broadcast-Empfänger keine Hintergrundthreads mit langer Ausführungszeit initiieren.
Das System kann den Prozess jederzeit nach onReceive() beenden, um Arbeitsspeicher freizugeben, und dabei den erstellten Thread beenden. Um den Prozess aktiv zu halten, planen Sie einen
JobService vom Empfänger mit dem JobScheduler, damit das
System weiß, dass der Prozess noch ausgeführt wird. Weitere Informationen
finden Sie unter Hintergrundaufgaben.
Broadcasts senden
Android bietet zwei Möglichkeiten, wie Apps Broadcasts senden können:
- Die
sendOrderedBroadcast(Intent, String)Methode sendet Broadcasts jeweils an einen Empfänger. Da jeder Empfänger nacheinander ausgeführt wird, kann er ein Ergebnis an den nächsten Empfänger weitergeben. Er kann den Broadcast auch vollständig abbrechen, sodass er keine anderen Empfänger erreicht. Sie können die Reihenfolge steuern, in der Empfänger innerhalb desselben App-Prozesses ausgeführt werden. Verwenden Sie dazu das Attributandroid:prioritydes entsprechenden Intent-Filters. Empfänger mit derselben Priorität werden in einer beliebigen Reihenfolge ausgeführt. - Die
sendBroadcast(Intent)Methode sendet Broadcasts in einer nicht definierten Reihenfolge an alle Empfänger. Das wird als normaler Broadcast bezeichnet. Diese Methode ist effizienter, aber Empfänger können keine Ergebnisse von anderen Empfängern lesen, Daten weitergeben, die sie vom Broadcast erhalten haben, oder den Broadcast abbrechen.
Das folgende Code-Snippet zeigt, wie Sie einen Broadcast senden, indem Sie einen
Intent erstellen und sendBroadcast(Intent) aufrufen.
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);
Die Nachricht an alle ist in einem Intent-Objekt enthalten. Der String action des Intents muss die Java-Paketnamensyntax der App enthalten und das Broadcast-Ereignis eindeutig identifizieren. Mit putExtra(String, Bundle) können Sie dem
Intent zusätzliche Informationen anhängen. Sie können einen Broadcast auch auf
eine Reihe von Apps in derselben Organisation beschränken, indem Sie setPackage(String) für
den Intent aufrufen.
Broadcasts mit Berechtigungen einschränken
Mit Berechtigungen können Sie Broadcasts auf die Apps beschränken, die bestimmte Berechtigungen haben. Sie können Einschränkungen für den Absender oder den Empfänger eines Broadcasts erzwingen.
Broadcasts mit Berechtigungen senden
Wenn Sie sendBroadcast(Intent, String) oder
sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String,
Bundle)
aufrufen, können Sie einen Berechtigungsparameter angeben. Nur Empfänger, die diese
Berechtigung mit dem <uses-permission> Tag in ihrem Manifest angefordert haben, können den
Broadcast empfangen. Wenn die Berechtigung gefährlich ist, müssen Sie sie erteilen, bevor der Empfänger den Broadcast empfangen kann. Der folgende Code sendet beispielsweise einen Broadcast mit einer Berechtigung:
Kotlin
context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION)
Java
context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION);
Damit die empfangende App den Broadcast empfangen kann, muss sie die Berechtigung so anfordern:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Sie können entweder eine vorhandene Systemberechtigung wie
BLUETOOTH_CONNECT angeben oder mit dem
<permission> Element eine benutzerdefinierte Berechtigung definieren. Informationen zu Berechtigungen und Sicherheit im
Allgemeinen finden Sie unter den Systemberechtigungen.
Broadcasts mit Berechtigungen empfangen
Wenn Sie beim Registrieren eines Übertragungsempfängers einen Berechtigungsparameter angeben
(entweder mit
registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) oder im
<receiver> Tag im Manifest), können nur Absender, die die Berechtigung mit dem <uses-permission> Tag in ihrem
Manifest angefordert haben, einen Intent an den Empfänger senden. Wenn die Berechtigung gefährlich ist, muss sie dem Absender auch erteilt werden.
Angenommen, Ihre empfangende App hat einen im Manifest deklarierten Empfänger:
<!-- 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>
Oder Ihre empfangende App hat einen kontextregistrierten Empfänger:
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
);
Damit die sendende App Broadcasts an diese Empfänger senden kann, muss sie die Berechtigung so anfordern:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Broadcasts innerhalb desselben Prozesses vermeiden
Broadcasts sind als Interprocess Communication (IPC) konzipiert, um Nachrichten zwischen verschiedenen Apps oder zwischen dem System und Apps zu senden. Das Senden eines Broadcasts von einem Prozess an einen Empfänger, der innerhalb desselben Prozesses ausgeführt wird, ist sehr ineffizient, verursacht unnötigen Systemaufwand und wird dringend abgeraten.
In zwei häufigen Szenarien senden Apps Broadcasts an sich selbst:
Kommunikation zwischen Komponenten im selben Prozess: Beispielsweise das Übergeben von Ereignissen oder Daten zwischen Aktivitäten, Fragmenten, Diensten oder Hintergrundthreads. Verwenden Sie anstelle von Broadcasts Standardmechanismen für die In-Process- Kommunikation wie das Beobachtermuster oder reaktive Streams:
- Kotlin-Flows (
SharedFlowundStateFlow): Eine moderne, idiomatische Lösung in Kotlin zum Senden und Beobachten von Ereignisstreams oder Statusaktualisierungen über Coroutinen und Komponenten in Ihrer App hinweg. - Gemeinsam genutztes
ViewModel: Ermöglicht die Freigabe von Daten und Ereignissen zwischen verschiedenen UI-Komponenten (z. B. Fragmenten oder zusammensetzbaren Funktionen) innerhalb derselben Aktivität. - Callbacks und Listener: Standardmäßige Interface-Callbacks oder Funktions verweise, die direkt zwischen Komponenten übergeben oder in einem zentralen Repository oder Controller registriert werden.
- Kotlin-Flows (
Systemereignisse, Jobs oder Alarme verarbeiten: Beispielsweise einen geplanten Job, Alarm oder System-Callback empfangen und dann einen Broadcast senden, um die eigentliche Arbeit auszulösen. Senden Sie keinen Broadcast, sondern führen Sie die Arbeit direkt in dieser Job- (z. B.
JobServiceoder WorkManager Worker), Alarm-Handler- oder System-Callback-Komponente aus oder delegieren Sie sie direkt an die Klassen der Geschäftslogik Ihrer App.
Wenn das System einen Selbst-Broadcast erkennt, versucht es möglicherweise, die Zustellung zu optimieren, indem es ihn innerhalb des Prozesses umleitet. Das ist jedoch immer noch weniger effizient als die oben beschriebenen Alternativen für die In-Process-Kommunikation. Sie sollten diese Alternativen stattdessen verwenden.
Weitere Informationen zum Entwerfen der Kommunikation zwischen App-Komponenten finden Sie unter dem Leitfaden zur App-Architektur.
Sicherheitsaspekte
Hier sind einige Sicherheitsaspekte für das Senden und Empfangen von Broadcasts:
Wenn viele Apps in ihrem Manifest registriert sind, um denselben Broadcast zu empfangen, kann das System viele Apps starten, was sich erheblich auf die Geräteleistung und die Nutzerfreundlichkeit auswirkt. Um das zu vermeiden, sollten Sie die Kontextregistrierung der Manifestdeklaration vorziehen. Manchmal erzwingt das Android-System selbst die Verwendung von kontextregistrierten Empfängern. Der
CONNECTIVITY_ACTIONBroadcast wird beispielsweise nur an kontextregistrierte Empfänger zugestellt.Senden Sie keine vertraulichen Informationen mit einem impliziten Intent. Jede App kann die Informationen lesen, wenn sie sich für den Empfang des Broadcasts registriert. Es gibt drei Möglichkeiten, zu steuern, wer Ihre Broadcasts empfangen kann:
- Sie können beim Senden eines Broadcasts eine Berechtigung angeben.
- Unter Android 4.0 (API-Level 14) und höher können Sie beim Senden eines Broadcasts mit
setPackage(String)ein Paket angeben. Das System beschränkt den Broadcast auf die Apps, die dem Paket entsprechen.
Wenn Sie einen Empfänger registrieren, kann jede App potenziell schädliche Broadcasts an den Empfänger Ihrer App senden. Es gibt mehrere Möglichkeiten, die Broadcasts zu beschränken, die Ihre App empfängt:
- Sie können beim Registrieren eines Übertragungsempfängers eine Berechtigung angeben.
- Für im Manifest deklarierte Empfänger können Sie das android:exported Attribut auf „false“ im Manifest setzen. Der Empfänger empfängt keine Broadcasts von Quellen außerhalb der App.
Der Namespace für Broadcast-Aktionen ist global. Achten Sie darauf, dass Aktionsnamen und andere Strings in einem Namespace geschrieben sind, der Ihnen gehört. Andernfalls kann es zu unbeabsichtigten Konflikten mit anderen Apps kommen.
Da die Methode
onReceive(Context, Intent)eines Empfängers im Hauptthread ausgeführt wird, sollte sie schnell ausgeführt werden und zurückkehren. Wenn Sie Aufgaben mit langer Ausführungszeit ausführen müssen, sollten Sie vorsichtig sein, Threads zu erstellen oder Hintergrunddienste zu starten, da das System den gesamten Prozess beenden kann, nachdemonReceive()zurückgekehrt ist. Weitere Informationen finden Sie unter Auswirkungen auf den Prozessstatus. Für Aufgaben mit langer Ausführungszeit empfehlen wir Folgendes:- Rufen Sie
goAsync()in der MethodeonReceive()Ihres Empfängers auf und übergeben SieBroadcastReceiver.PendingResultan einen Hintergrund thread. Dadurch bleibt der Broadcast aktiv, nachdemonReceive()zurückgekehrt ist. Auch bei dieser Methode erwartet das System jedoch, dass Sie den Broadcast sehr schnell (innerhalb von 10 Sekunden) beenden. Sie können Aufgaben in einen anderen Thread verschieben, um zu vermeiden, dass der Hauptthread unterbrochen wird. - Planen Sie einen Job mit dem
JobScheduler. Weitere Informationen finden Sie unter Intelligente Jobplanung.
- Rufen Sie
Starten Sie keine Aktivitäten von Broadcast-Empfängern aus, da dies die Nutzerfreundlichkeit beeinträchtigt, insbesondere wenn es mehr als einen Empfänger gibt. Erwägen Sie stattdessen, eine Benachrichtigung anzuzeigen.