Broadcasts – Übersicht

Android-Apps senden und empfangen Broadcast-Nachrichten vom Android-System und von anderen Android-Apps. Das funktioniert ähnlich wie beim Publish-Subscribe-Muster. Das System und Apps senden in der Regel Broadcasts, wenn bestimmte Ereignisse eintreten. Das Android-System sendet beispielsweise Broadcasts, wenn verschiedene Systemereignisse eintreten, z. B. beim Systemstart oder beim Aufladen des Geräts. Apps senden auch benutzerdefinierte Broadcasts, um andere Apps über etwas zu informieren, das für sie von Interesse sein könnte, z. B. einen neuen Datendownload.

Apps können sich registrieren, um bestimmte Broadcasts zu empfangen. Wenn eine Broadcast-Nachricht gesendet wird, leitet das System sie automatisch an Apps weiter, die für den Empfang dieser Art von Broadcast-Nachricht registriert sind.

Im Allgemeinen können Broadcasts als Nachrichtensystem für Apps und außerhalb des normalen Nutzerablaufs verwendet werden. Sie müssen jedoch darauf achten, dass Sie die Möglichkeit, auf Broadcasts zu reagieren und Jobs im Hintergrund auszuführen, nicht missbrauchen, da dies zu einer langsamen Systemleistung führen kann.

Systemnachrichten

Das System sendet automatisch Broadcasts, wenn verschiedene Systemereignisse eintreten, z. B. wenn das System in den Flugmodus wechselt oder den Flugmodus verlässt. Alle abonnierten Apps empfangen 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. Die Absicht kann auch zusätzliche Informationen enthalten, die im Feld „extra“ gebündelt sind. Der Intent „Flugmodus“ enthält beispielsweise ein boolesches Extra, das angibt, ob der Flugmodus aktiviert ist.

Weitere Informationen zum Lesen von Intents und zum Abrufen des Aktions-Strings aus einem Intent finden Sie unter Intents und Intent-Filter.

Systemnachrichtenaktionen

Eine vollständige Liste der System-Broadcast-Aktionen finden Sie in der Datei BROADCAST_ACTIONS.TXT im Android SDK. Jeder Broadcast-Aktion ist ein konstantes Feld 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 Konstantfeld verfügbar.

Änderungen bei 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 wird die Reihenfolge der Broadcast-Zustellung bei Verwendung des Attributs android:priority oder IntentFilter.setPriority() über verschiedene Prozesse hinweg nicht garantiert. 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, SYSTEM_HIGH_PRIORITY als Broadcast-Priorität festlegen.

Android 14

Wenn sich Apps im Cache-Zustand befinden, optimiert das System die Übertragung von Broadcasts für die Systemintegrität. Das System verschiebt beispielsweise weniger wichtige System-Broadcasts wie ACTION_SCREEN_ON, während sich die App im Cache befindet. Sobald die App vom Cache-Status in einen aktiven Prozesslebenszyklus wechselt, liefert das System alle verzögerten Broadcasts aus.

Wichtige Broadcasts, die im Manifest deklariert sind, entfernen Apps vorübergehend aus dem Cache für die Zustellung.

Android 9

Ab Android 9 (API-Level 28) werden bei der NETWORK_STATE_CHANGED_ACTION-Broadcast keine Informationen zum Standort des Nutzers oder personenbezogene Daten empfangen.

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) unterliegt das System zusätzlichen Einschränkungen für im Manifest deklarierte Empfänger.

Wenn Ihre App auf Android 8.0 oder höher ausgerichtet ist, können Sie das Manifest nicht verwenden, um einen Empfänger für die meisten impliziten Broadcasts (Broadcasts, die nicht speziell auf Ihre App ausgerichtet sind) zu deklarieren. Sie können weiterhin einen kontextregistrierten Receiver 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.

Übertragungen empfangen

Apps können Broadcasts auf zwei Arten empfangen: über kontextregistrierte Empfänger und über im Manifest deklarierte Empfänger.

Kontextregistrierte Empfänger

Kontextregistrierte Empfänger empfangen Broadcasts, solange ihr Registrierungskontext gültig ist. Dies geschieht 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, erhalten Sie Broadcasts, solange die Aktivität aktiv bleibt. Wenn Sie sich mit dem Anwendungskontext registrieren, erhalten Sie Broadcasts, solange die App ausgeführt wird.

So registrieren Sie einen Receiver mit einem Kontext:

  1. Fügen Sie in die Build-Datei auf Modulebene Ihrer App Version 1.9.0 oder höher der AndroidX Core-Bibliothek ein:

    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")
    }
  2. Erstellen Sie eine Instanz von BroadcastReceiver:

    Kotlin

    val myBroadcastReceiver = MyBroadcastReceiver()
    

    Java

    MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();
    
  3. 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");
    
  4. Wählen Sie aus, ob der Übertragungsempfänger exportiert und für andere Apps auf dem Gerät sichtbar sein soll. Wenn dieser Receiver 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 Receiver stattdessen nur auf Broadcasts wartet, die von Ihrer App gesendet werden, verwenden Sie das Flag RECEIVER_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;
    
  5. Registrieren Sie den Empfänger, indem Sie registerReceiver() anrufen:

    Kotlin

    ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags)
    

    Java

    ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags);
    
  6. Wenn Sie keine Broadcasts mehr erhalten möchten, rufen Sie unregisterReceiver(android.content.BroadcastReceiver) an. Registrieren Sie den Receiver ab, wenn Sie ihn nicht mehr benötigen oder der Kontext nicht mehr gültig ist.

Übertragungsempfänger abmelden

Solange der Übertragungsempfänger registriert ist, enthält er einen Verweis auf den Kontext, mit dem Sie ihn registriert haben. Dies kann zu Lecks führen, wenn der registrierte Bereich des Empfängers den Bereich des Context-Lebenszyklus überschreitet. Das kann beispielsweise passieren, wenn Sie einen Receiver in einem Activity-Bereich registrieren, aber vergessen, die Registrierung aufzuheben, wenn das System die Activity beendet. Melden Sie Ihren Übertragungsempfänger daher immer ab.

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 am Ergebnis interessiert sind. Wählen Sie den kleinstmöglichen Empfängerbereich aus:

  • LifecycleResumeEffect oder Aktivitäts-Lifecycle-Methoden onResume/onPause: Der Übertragungsempfänger empfängt nur Updates, wenn sich die App im fortgesetzten Zustand befindet.
  • LifecycleStartEffect oder Aktivitäts-Lifecycle-Methoden onStart/onStop: Der Übertragungsempfänger empfängt nur Updates, wenn sich die App im fortgesetzten Zustand befindet.
  • DisposableEffect: Der Übertragungsempfänger empfängt nur Updates, wenn sich das Composable im Kompositionsbaum befindet. Dieser Bereich ist nicht an den Bereich des Aktivitätslebenszyklus angehängt. Registrieren Sie den Receiver im Anwendungskontext. Das liegt daran, dass das Composable theoretisch den Aktivitätslebenszyklus überdauern und die Aktivität verloren gehen könnte.
  • Aktivität onCreate/onDestroy: Der Übertragungsempfänger empfängt Updates, während sich die Aktivität im Status „Erstellt“ befindet. Melden Sie sich in onDestroy() und nicht in onSaveInstanceState(Bundle) ab, da diese möglicherweise nicht aufgerufen wird.
  • Benutzerdefinierter Bereich: Sie können beispielsweise einen Receiver in Ihrem ViewModel-Bereich registrieren, damit er die Neuerstellung von Aktivitäten übersteht. Verwenden Sie den Anwendungskontext, um den Empfänger zu registrieren, da der Empfänger den Lebenszyklusbereich der Aktivität überdauern und die Aktivität leaken kann.

Zustandsorientierte und zustandslose Composables erstellen

Compose hat zustandsorientierte und zustandslose Composables. Durch das Registrieren oder Aufheben der Registrierung eines Übertragungsempfängers in einem Composable wird es zustandsbehaftet. Die Composable ist keine deterministische Funktion, die bei Übergabe derselben Parameter denselben Inhalt rendert. Der interne Status kann sich basierend auf Aufrufen des registrierten Broadcast-Empfängers ändern.

Als Best Practice in Compose empfehlen wir, Ihre Composables in zustandsbehaftete und zustandslose Versionen aufzuteilen. Daher empfehlen wir, die Erstellung des Übertragungsempfängers aus einem Composable herauszuziehen, damit er zustandslos ist:

@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 in Ihrem 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:

  1. Geben Sie das Element <receiver> 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 dein Empfänger abonniert.

  2. Erstellen Sie eine Unterklasse von BroadcastReceiver und implementieren Sie onReceive(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 Systempaketmanager registriert den Receiver, wenn die App installiert wird. Der Receiver wird dann zu einem separaten Einstiegspunkt in Ihre App. Das bedeutet, dass das System die App starten und den Broadcast senden kann, wenn die App nicht ausgeführt wird.

Das System erstellt ein neues BroadcastReceiver-Komponentenobjekt, um jede empfangene Broadcast-Nachricht zu verarbeiten. Dieses Objekt ist nur für die Dauer des Aufrufs 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 in Betrieb ist oder nicht, wirkt sich auf den darin enthaltenen Prozess aus, was die Wahrscheinlichkeit, dass das System beendet wird, verändern kann. Ein Vordergrundprozess führt die Methode onReceive() eines Empfängers aus. Das System führt den Prozess aus, es sei denn, es besteht eine extreme Arbeitsspeicherauslastung.

Das System deaktiviert BroadcastReceiver nach onReceive(). Die Bedeutung des Hostprozesses des Empfängers hängt von seinen App-Komponenten ab. Wenn in diesem Prozess nur ein im Manifest deklarierter Empfänger gehostet wird, kann das System ihn nach onReceive() beenden, um Ressourcen für andere, wichtigere Prozesse freizugeben. Das ist häufig bei Apps der Fall, mit denen der Nutzer noch nie oder in letzter Zeit nicht interagiert hat.

Daher sollten Broadcast-Empfänger keine Hintergrundthreads mit langer Ausführungszeit starten. Das System kann den Prozess jederzeit nach onReceive() beenden, um Speicherplatz freizugeben, und den erstellten Thread beenden. Damit der Prozess aktiv bleibt, plane mit JobScheduler eine JobService vom Empfänger aus, damit das System weiß, dass der Prozess noch aktiv ist. Weitere Informationen finden Sie unter Hintergrundaufgaben – Übersicht.

Übertragungen senden

Android bietet zwei Möglichkeiten für Apps, Broadcasts zu senden:

  • Mit der Methode sendOrderedBroadcast(Intent, String) werden Broadcasts jeweils an einen Empfänger gesendet. Da jeder Empfänger nacheinander ausgeführt wird, kann er ein Ergebnis an den nächsten Empfänger weitergeben. Außerdem kann die Übertragung vollständig abgebrochen werden, sodass sie nicht auf anderen Empfängern wiedergegeben wird. Sie können die Reihenfolge steuern, in der Empfänger im selben App-Prozess ausgeführt werden. Verwenden Sie dazu das Attribut android:priority des entsprechenden Intent-Filters. Empfänger mit derselben Priorität werden in beliebiger Reihenfolge ausgeführt.
  • Die Methode sendBroadcast(Intent) sendet Broadcasts in einer nicht definierten Reihenfolge an alle Empfänger. Das wird als normale Übertragung bezeichnet. Das ist effizienter, bedeutet aber, dass Empfänger keine Ergebnisse von anderen Empfängern lesen, vom Broadcast empfangene Daten weiterleiten oder den Broadcast abbrechen können.

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 ein Intent-Objekt eingebunden. Der action-String 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 eine Broadcast-Nachricht auch auf eine Reihe von Apps in derselben Organisation beschränken, indem Sie setPackage(String) für den Intent aufrufen.

Übertragungen 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 Empfänger einer Broadcast-Nachricht 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 Tag <uses-permission> 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. Mit dem folgenden Code wird beispielsweise ein Broadcast mit einer Berechtigung gesendet:

Kotlin

context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION)

Java

context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION);

Damit die empfangende App die Broadcast-Nachricht 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 eine benutzerdefinierte Berechtigung mit dem Element <permission> definieren. Informationen zu Berechtigungen und Sicherheit im Allgemeinen finden Sie unter Systemberechtigungen.

Übertragungen mit Berechtigungen empfangen

Wenn Sie beim Registrieren eines Übertragungsempfängers einen Berechtigungsparameter angeben (entweder mit registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) oder im <receiver>-Tag in Ihrem Manifest), können nur Broadcaster, 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 auch dem Broadcaster gewährt werden.

Angenommen, Ihre Empfänger-App hat einen im Manifest deklarierten Empfänger wie folgt:

<!-- 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 wie folgt:

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 Mechanismus für die Interprozesskommunikation (IPC) konzipiert, um Nachrichten zwischen verschiedenen Apps oder zwischen dem System und Apps zu senden. Das Senden einer Selbst-Broadcast, bei der alle Empfänger im selben Prozess wie der Sender ausgeführt werden, ist sehr ineffizient, verursacht unnötigen System-Aufwand und wird dringend abgeraten.

Zwei häufige Szenarien, in denen Apps Broadcasts an sich selbst senden:

  • Kommunikation zwischen Komponenten im selben Prozess: Zum Beispiel das Übergeben von Ereignissen oder Daten zwischen Aktivitäten, Fragmenten, Diensten oder Hintergrundthreads. Verwenden Sie anstelle von Broadcasts standardmäßige In-Process-Kommunikationsmechanismen wie das Observer-Muster oder reaktive Streams:

    • Kotlin-Flows (SharedFlow und StateFlow): Eine moderne, idiomatische Lösung in Kotlin zum Ausgeben und Beobachten von Event-Streams oder Statusaktualisierungen über Koroutinen und Komponenten in Ihrer App hinweg.
    • Gemeinsam ViewModel: Ermöglicht die gemeinsame Nutzung von Daten und Ereignissen zwischen verschiedenen UI-Komponenten (z. B. Fragmenten oder Composables) innerhalb derselben Aktivität.
    • Callbacks und Listener: Standardmäßige Interface-Callbacks oder Funktionsreferenzen, die direkt zwischen Komponenten übergeben oder in einem zentralen Repository oder Controller registriert werden.
  • Systemereignisse, Jobs oder Alarme verarbeiten: Zum Beispiel einen geplanten Job, Alarm oder System-Callback empfangen und dann einen Broadcast senden, um die eigentliche Arbeit auszulösen. Anstatt eine Broadcast-Nachricht zu senden, sollten Sie die Arbeit direkt in diesem Job erledigen, z. B. in einem JobService- oder WorkManager-Worker, einem Alarm-Handler oder einer System-Callback-Komponente, oder die Aufgabe direkt an die Klassen der Geschäftslogik Ihrer App delegieren.

Auf Geräten mit Android 17 QPR2 oder höher werden Self-Broadcasts effizienter zugestellt, indem sie an den Sendeprozess zurückgegeben werden, der sie an seine eigenen Empfänger im Hauptthread sendet. Das Senden eines Self-Broadcasts erhöht die Wichtigkeit Ihres Prozesses nicht und verhindert auch nicht, dass ein im Cache gespeicherter Prozess eingefroren wird. Verlassen Sie sich daher nicht auf Self-Broadcasts, um Ihre App am Laufen zu halten oder Aufgaben im Hintergrund auszuführen. Selbst mit dieser Optimierung sind Self-Broadcasts weniger effizient als In-Process-Kommunikationsmechanismen. Verwenden Sie daher diese Alternativen.

Weitere Informationen zum Entwerfen der Kommunikation zwischen App-Komponenten finden Sie im Leitfaden zur App-Architektur.

Sicherheitsaspekte

Hier sind einige Sicherheitsaspekte für das Senden und Empfangen von Broadcasts:

  • Wenn viele Apps registriert sind, um denselben Broadcast in ihrem Manifest zu empfangen, kann dies dazu führen, dass das System viele Apps startet, was sich erheblich auf die Geräteleistung und die Nutzerfreundlichkeit auswirkt. Um dies zu vermeiden, sollten Sie die Kontextregistrierung der Manifestdeklaration vorziehen. Manchmal erzwingt das Android-System selbst die Verwendung von kontextregistrierten Broadcast-Empfängern. So wird die CONNECTIVITY_ACTION-Broadcast beispielsweise nur an kontextregistrierte Empfänger gesendet.

  • Senden Sie keine vertraulichen Informationen über eine implizite Intention. Jede App kann die Informationen lesen, wenn sie sich für den Empfang des Broadcasts registriert. Es gibt drei Möglichkeiten, festzulegen, wer Ihre Broadcasts empfangen kann:

    • Sie können beim Senden einer Broadcast-Nachricht eine Berechtigung angeben.
    • Unter Android 4.0 (API-Level 14) und höher können Sie beim Senden eines Broadcasts mit setPackage(String) ein package 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 von Ihrer App empfangenen Broadcasts einzuschränken:

    • Sie können eine Berechtigung angeben, wenn Sie einen Übertragungsempfänger registrieren.
    • Für im Manifest deklarierte Receiver können Sie das Attribut android:exported im Manifest auf „false“ 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 werden, der Ihnen gehört. Andernfalls kann es zu unbeabsichtigten Konflikten mit anderen Apps kommen.

  • Da die onReceive(Context, Intent)-Methode eines Empfängers im Hauptthread ausgeführt wird, sollte sie schnell ausgeführt und zurückgegeben werden. Wenn Sie lang andauernde Aufgaben ausführen müssen, sollten Sie keine Threads erstellen oder Hintergrunddienste starten, da das System den gesamten Prozess nach der Rückgabe von onReceive() beenden kann. Weitere Informationen finden Sie unter Auswirkungen auf den Prozessstatus. Für Vorgänge mit langer Laufzeit empfehlen wir Folgendes:

    • Rufen Sie goAsync() in der onReceive()-Methode des Receivers auf und übergeben Sie BroadcastReceiver.PendingResult an einen Hintergrundthread. So bleibt die Übertragung aktiv, wenn du von onReceive() zurückkehrst. Auch bei diesem Ansatz erwartet das System, dass du die Übertragung sehr schnell (in weniger als 10 Sekunden) beendest. Sie können damit Aufgaben in einen anderen Thread verschieben, um Störungen im Hauptthread zu vermeiden.
    • Einen Job mit JobScheduler planen Weitere Informationen finden Sie unter Intelligent Job Scheduling.
  • Starten Sie keine Aktivitäten über Broadcast-Empfänger, da dies die Nutzerfreundlichkeit beeinträchtigt, insbesondere wenn es mehr als einen Empfänger gibt. Stattdessen können Sie eine Benachrichtigung anzeigen.