18 Broadcast Receiver

Ein Broadcast Receiver (oder kurz Receiver) in Android ist eine Komponente, die auf system- oder anwendungsspezifische Ereignisse oder Informationen (sogenannte Broadcasts) reagiert. Broadcasts können von der Android-Plattform selbst, von Systemdiensten oder von Anwendungen ausgelöst werden und enthalten oft Informationen über eine Änderung des Zustands, wie beispielsweise eine niedrige Akkuladung, eine Änderung der Netzwerkverbindung oder das Herunterfahren des Geräts.

Ein Broadcast Receiver wird in einer App implementiert, indem eine Unterklasse der BroadcastReceiver-Klasse erstellt und die Methode onReceive(Context, Intent) überschrieben wird. Die onReceive()-Methode wird aufgerufen, wenn ein Broadcast empfangen wird, auf den der Receiver abonniert ist.

Hier ist ein einfaches Beispiel für einen Broadcast Receiver:

class MyBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        val action = intent?.action

        if (action == Intent.ACTION_POWER_CONNECTED) {
            Toast.makeText(context, "Das Gerät wird aufgeladen", Toast.LENGTH_SHORT).show()
        } else if (action == Intent.ACTION_POWER_DISCONNECTED) {
            Toast.makeText(context, "Das Gerät wird nicht mehr aufgeladen", Toast.LENGTH_SHORT).show()
        }
    }
}

In diesem Beispiel zeigt der Receiver eine Toast-Nachricht an, wenn das Gerät an eine Stromquelle angeschlossen oder von einer solchen getrennt wird.

Ein Broadcast Receiver muss im AndroidManifest.xml-Datei deklariert werden, damit er auf Broadcasts reagieren kann. Dies wird normalerweise mit einem <receiver>-Element im <application>-Element des Manifests gemacht, wobei das android:name-Attribut den vollqualifizierten Klassennamen des Receivers angibt:

<receiver android:name=".MyBroadcastReceiver">
    <intent-filter>
        <action android:name="android.intent.action.POWER_CONNECTED"/>
        <action android:name="android.intent.action.POWER_DISCONNECTED"/>
    </intent-filter>
</receiver>

In diesem Beispiel abonniert der Receiver die POWER_CONNECTED- und POWER_DISCONNECTED-Intents mithilfe eines Intent-Filters.

18.1 Broadcast Receiver seit Oreo

Mit Android 8.0 (API-Ebene 26) änderte Google die Art und Weise, wie Broadcast Receivers funktionieren, insbesondere solche, die auf systemweite Broadcasts reagieren. Bis zu diesem Zeitpunkt konnten Sie einen Receiver im Manifest deklarieren und er würde auf die entsprechenden Intents reagieren, auch wenn Ihre App nicht im Vordergrund war. Ab Android 8.0 ist dieser Ansatz jedoch eingeschränkt.

18.1.1 Manifest-deklarierte Receiver

Für die meisten Broadcasts ist es nun nicht mehr möglich, auf diese zu reagieren, wenn sie im Manifest deklariert sind, es sei denn, die App läuft im Vordergrund. Hier ist ein einfaches Beispiel für einen Manifest-deklarierten Receiver, der auf das ACTION_AIRPLANE_MODE_CHANGED-Broadcast reagiert:

<receiver android:name=".MyBroadcastReceiver" android:exported="false">
    <intent-filter>
        <action android:name="android.intent.action.AIRPLANE_MODE"/>
    </intent-filter>
</receiver>

Und hier ist die zugehörige Kotlin-Klasse:

class MyBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (Intent.ACTION_AIRPLANE_MODE_CHANGED == intent?.action) {
            val isAirplaneModeOn = intent.getBooleanExtra("state", false)
            // Reagieren Sie hier auf die Änderung des Flugmodus
        }
    }
}

18.2 Dynamisch registrierte Receiver

Für die meisten Broadcasts, insbesondere die, die außerhalb der App generiert werden, müssen Sie jetzt einen dynamisch registrierten Receiver verwenden

. Ein dynamisch registrierter Receiver wird in der Kotlin-Code Ihrer App und nicht im Manifest deklariert. Hier ist ein Beispiel:

class MainActivity : AppCompatActivity() {
    private lateinit var myBroadcastReceiver: BroadcastReceiver

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        myBroadcastReceiver = MyBroadcastReceiver()
    }

    override fun onStart() {
        super.onStart()
        val intentFilter = IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)
        registerReceiver(myBroadcastReceiver, intentFilter)
    }

    override fun onStop() {
        super.onStop()
        unregisterReceiver(myBroadcastReceiver)
    }
}

In diesem Beispiel wird der Receiver in der onStart() Methode der Aktivität registriert und in der onStop() Methode der Aktivität de-registriert. Dies stellt sicher, dass der Receiver nur dann auf Intents reagiert, wenn die Aktivität im Vordergrund ist (zwischen onStart() und onStop()).

Beachten Sie, dass einige Broadcasts weiterhin von im Manifest deklarierten Receivern empfangen werden können, auch wenn die App nicht im Vordergrund ist. Dies gilt jedoch nur für sogenannte “statische” Broadcasts, die sich auf systemweite Ereignisse beziehen, die auch dann relevant sind, wenn die App nicht im Vordergrund ist, wie z.B. das Boot-Fertig-Broadcast ACTION_BOOT_COMPLETED. In den meisten Fällen sollten Sie jedoch einen dynamisch registrierten Receiver verwenden, um sicherzustellen, dass Ihre App korrekt funktioniert, unabhängig davon, welche Android-Version der Benutzer hat.