Broadcasts – Übersicht

Android-Apps senden und empfangen Broadcast-Nachrichten vom Android-System und anderen Android-Apps, ähnlich 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 benachrichtigen, das für sie von Interesse sein könnte (z. B. ein neuer Download).

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 reagieren 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. Die Absicht kann auch zusätzliche Informationen enthalten, die im Feld „extra“ gebündelt sind. Die Absicht für den Flugmodus enthält beispielsweise ein boolesches Extra, das angibt, ob der Flugmodus aktiviert ist oder nicht.

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

Mit der Weiterentwicklung 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 die 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 zu gewährleisten. 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.

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. Dies 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:

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

    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 Empfänger auf Broadcasts wartet, die vom System oder von anderen Apps gesendet werden – auch von anderen Apps, deren Inhaber Sie sind –, verwenden Sie das Flag RECEIVER_EXPORTED. Wenn dieser Empfänger 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 mit registerReceiver():

    Kotlin

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

    Java

    ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags);
    
  6. Wenn Sie keine Broadcasts mehr empfangen möchten, rufen Sie unregisterReceiver(android.content.BroadcastReceiver) auf. 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 Broadcast-Empfä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. Dies kann beispielsweise auftreten, wenn Sie einen Empfänger im Bereich einer Aktivität registrieren, aber vergessen, die Registrierung aufzuheben, wenn das System die Aktivität zerstört. Heben Sie daher immer die Registrierung Ihres Broadcast-Empfä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:

  • LifecycleResumeEffect oder die Lebenszyklusmethoden onResume/onPause der Aktivität: Der Übertragungsempfänger erhält nur Updates, wenn sich die App im fortgesetzten Zustand befindet.
  • LifecycleStartEffect oder die Lebenszyklusmethoden onStart/onStop der Aktivität: 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ätslebenszyklus gebunden. Registrieren Sie den Empfänger im Anwendungskontext. Dies liegt daran, dass die zusammensetzbare Funktion theoretisch den Aktivitätslebenszyklus überdauern und die Aktivität lecken könnte.
  • onCreate/onDestroy der Activity: Der Übertragungsempfänger erhält Updates, wenn sich die Activity im erstellten Zustand befindet. Heben Sie die Registrierung in onDestroy() und nicht in onSaveInstanceState(Bundle) auf, da diese möglicherweise nicht aufgerufen wird.
  • Ein benutzerdefinierter Bereich: Sie können beispielsweise einen Empfänger im Bereich ViewModel registrieren, 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.

Zustandsbehaftete und zustandslose zusammensetzbare Funktionen erstellen

Compose hat zustandsbehaftete und zustandslose zusammensetzbare Funktionen. Wenn Sie einen Übertragungsempfänger innerhalb einer zusammensetzbaren Funktion registrieren oder die Registrierung aufheben, wird er zustandsbehaftet. 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 zustandsbehaftete und zustandslose Versionen aufzuteilen. Wir empfehlen daher, die Erstellung des Übertragungsempfängers aus einer zusammensetzbaren 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:

  1. 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.

  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 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. Dies ist häufig bei Apps der Fall, mit denen der Nutzer noch nie oder seit Kurzem nicht mehr interagiert hat.

Daher sollten Übertragungsempfänger keine lang andauernden Hintergrundthreads starten. Das System kann den Prozess jederzeit nach onReceive() beenden, um Arbeitsspeicher freizugeben, und dabei den erstellten Thread beenden. Wenn Sie den Prozess aktiv halten möchten, 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 für Apps, Broadcasts zu senden:

  • 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 andere Empfänger nicht erreicht. Sie können die Reihenfolge steuern, in der Empfänger innerhalb desselben App-Prozesses ausgeführt werden. Verwenden Sie dazu das Attribut android:priority des entsprechenden Absichtsfilters. Empfänger mit derselben Priorität werden in beliebiger Reihenfolge ausgeführt.
  • Die sendBroadcast(Intent) Methode sendet Broadcasts in undefinierter Reihenfolge an alle Empfänger Dies 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 eine Absicht 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 String action der Absicht muss die Java-Paketnamenssyntax der App enthalten und das Broadcast-Ereignis eindeutig identifizieren. Mit putExtra(String, Bundle) können Sie der Absicht 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 die Absicht 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, eine Absicht 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 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 Interprocess Communication (IPC) konzipiert, um Nachrichten zwischen verschiedenen Apps oder zwischen dem System und Apps zu senden. Das Senden eines Selbst-Broadcasts, bei dem alle der Empfänger im selben Prozess ausgeführt werden, der den Broadcast gesendet hat, 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 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 Senden und Beobachten von Ereignisstreams oder Statusaktualisierungen über Coroutinen und Komponenten in Ihrer App hinweg.
    • Gemeinsames ViewModel: Ermöglicht die gemeinsame Nutzung 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.
  • 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 diesem Job (z. B. einem JobService oder WorkManager-Worker), Alarm-Handler oder der System-Callback-Komponente aus oder delegieren Sie sie direkt an die Klassen der Geschäftslogik Ihrer App.

Auf Geräten mit Android 17 QPR2 oder höher liefert das System Selbst-Broadcasts effizienter, indem es sie an den sendenden Prozess zurückgibt, der sie im Hauptthread an seine eigenen Empfänger liefert. Das Senden eines Selbst-Broadcasts erhöht die Wichtigkeit Ihres Prozesses nicht und verhindert nicht, dass ein im Cache gespeicherter Prozess eingefroren wird. Verlassen Sie sich daher nicht auf Selbst-Broadcasts, um Ihre App auszuführen oder Arbeit im Hintergrund zu erledigen. Wählen Sie stattdessen die entsprechende API für Ihre Aufgabe aus, wie unter Hintergrundaufgabenbeschrieben. Auch mit dieser Optimierung sind Selbst-Broadcasts weniger effizient als In-Process-Kommunikationsmechanismen. Verwenden Sie daher stattdessen diese Alternativen.

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 im Manifest registriert sind, um denselben Broadcast 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 Empfängern. Der CONNECTIVITY_ACTION Broadcast wird beispielsweise nur an kontextregistrierte Empfänger gesendet.

  • Senden Sie keine vertraulichen Informationen mit einer impliziten Absicht. 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 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 sind, dessen Inhaber Sie sind. 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 und zurückgegeben werden. Wenn Sie lang andauernde Aufgaben ausführen müssen, sollten Sie vorsichtig sein, Threads zu erstellen oder Hintergrunddienste zu starten, da das System den gesamten Prozess beenden kann, nachdem onReceive() zurückgegeben wurde. Weitere Informationen finden Sie unter Auswirkungen auf den Prozessstatus. So führen Sie lang andauernde Aufgaben aus:

    • Rufen Sie in der Methode onReceive() Ihres Empfängers goAsync() auf und übergeben Sie BroadcastReceiver.PendingResult an einen Hintergrund thread. Dadurch bleibt der Broadcast aktiv, nachdem onReceive() zurückgegeben wurde. Auch bei dieser Methode erwartet das System jedoch, dass Sie den Broadcast sehr schnell (innerhalb von 10 Sekunden) beenden. Sie können die Arbeit jedoch in einen anderen Thread verschieben, um zu vermeiden, dass der Hauptthread fehlerhaft funktioniert.
    • Planen Sie einen Job mit dem JobScheduler. Weitere Informationen finden Sie unter Intelligente Jobplanung.
  • Starten Sie keine Activities von Übertragungsempfängern, da dies die Nutzerfreundlichkeit beeinträchtigt, insbesondere wenn es mehrere Empfänger gibt. Erwägen Sie stattdessen, eine Benachrichtigung anzuzeigen.