Intents in Android: Kommunikation zwischen Komponenten
Intents sind Androids Boten zwischen Komponenten und Apps. Du lernst explizite und implizite Intents, Actions und typische Stolperfallen kennen.
In Android trifft selten eine Komponente alle Entscheidungen allein. Sobald du eine zweite Activity öffnest, eine Datei teilst oder den Browser aufrufen willst, kommt ein Intent ins Spiel. Dieses kleine Objekt ist das Bindeglied zwischen den Bausteinen deiner App und den Apps anderer Entwickler — und es ist eines der ersten Konzepte, das du wirklich verinnerlichen solltest, bevor du dich an Architecture Components, Navigation oder Deep Links wagst.
Was ist das?
Ein Intent ist die Beschreibung dessen, was passieren soll. Du sagst dem System nicht, wie eine Aktion ausgeführt werden muss, sondern nur, welche Absicht du verfolgst: eine neue Activity starten, einen Service anstoßen oder ein Broadcast verteilen. Das Android-Framework übernimmt den Rest, prüft Berechtigungen und liefert die Anfrage an die passende Komponente.
Du kannst dir Intents als Botschaften zwischen Bausteinen vorstellen — und zwar sowohl innerhalb deiner eigenen App als auch über App-Grenzen hinweg. Genau diese Trennung macht Android modular: Eine App muss nicht wissen, wer ihre Anfrage erfüllt, sie muss nur sagen, was sie braucht. Wenn deine News-App einen Link öffnen will, ist ihr egal, ob der Nutzer Chrome, Firefox oder einen Custom-Tab bevorzugt. Sie verschickt eine Absicht, das System routet sie weiter.
Wie funktioniert es?
Du unterscheidest zwei Hauptarten. Ein expliziter Intent benennt die Zielkomponente direkt, etwa eine konkrete Activity-Klasse. Diesen Typ verwendest du fast immer innerhalb deiner eigenen App, weil du weißt, was du ansteuern willst. Ein impliziter Intent dagegen beschreibt nur eine Aktion und überlässt es Android, einen passenden Empfänger zu finden. Typische Werte für Aktionen sind ACTION_VIEW, ACTION_SEND oder ACTION_DIAL.
Neben der Action kannst du weitere Bestandteile mitgeben: Daten als Uri, Kategorien wie CATEGORY_BROWSABLE, einen MIME-Type sowie Extras im Bundle. Beim Start prüft das System sogenannte Intent-Filter, die Komponenten in ihrem Manifest deklarieren. Passt mehr als ein Empfänger, zeigt Android einen Auswahldialog. Findet sich keiner, bleibt der Intent ungenutzt — dieses Risiko musst du im Code abfangen.
Seit Android 11 schränkt die Plattform die sogenannte Package Visibility ein: Du siehst nicht mehr automatisch alle Apps auf dem Gerät. Implizite Intents funktionieren weiter, aber für gezielte Abfragen über den PackageManager musst du die <queries>-Sektion im Manifest pflegen. Diese Änderung gehört zum modernen Android-Alltag und schützt die Privatsphäre der Nutzer.
In der Praxis
Stell dir vor, du baust eine News-App und willst einen Artikel im Browser öffnen. Das ist ein klassischer Fall für einen impliziten Intent mit ACTION_VIEW.
fun openArticle(context: Context, url: String) {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
if (intent.resolveActivity(context.packageManager) != null) {
context.startActivity(intent)
} else {
Toast.makeText(context, "Kein Browser gefunden", Toast.LENGTH_SHORT).show()
}
}
Für einen internen Detail-Screen nutzt du dagegen einen expliziten Intent. Du kennst die Zielklasse und kannst Daten direkt als Extras anhängen:
val intent = Intent(this, ArticleDetailActivity::class.java).apply {
putExtra("articleId", id)
}
startActivity(intent)
Häufige Stolperfallen
Die größte Falle ist der ungeprüfte implizite Intent. Wenn kein Empfänger registriert ist und du startActivity ohne Absicherung aufrufst, fängt sich deine App eine ActivityNotFoundException und stürzt ab. Prüfe daher mit resolveActivity oder kapsle den Aufruf in einen try-catch-Block.
Eine zweite Falle sind sensible Daten in Extras. Implizite Intents können von jeder App mit passendem Filter empfangen werden — schicke also keine Tokens, Passwörter oder personenbezogenen Inhalte in einen offenen Intent. Wenn du intern Daten austauschen willst, nimm einen expliziten Intent oder schütze den Empfänger über android:exported="false" und Permissions.
Eine dritte Falle ist die Wahl der Flags. FLAG_ACTIVITY_NEW_TASK brauchst du, wenn du aus einem Nicht-Activity-Kontext (etwa einem Service oder Application-Context) startest, sonst beschwert sich das System. Auch FLAG_ACTIVITY_CLEAR_TOP und FLAG_ACTIVITY_SINGLE_TOP haben spürbare Effekte auf den Backstack — teste das Verhalten lieber bewusst, statt zu raten.
Validierung im Test
Intents sind ein Paradebeispiel für testbares Verhalten. Mit Espresso und der Library androidx.test.espresso:espresso-intents prüfst du, ob deine App den richtigen Intent absetzt. Eine typische Assertion sieht so aus:
intended(allOf(
hasAction(Intent.ACTION_VIEW),
hasData(Uri.parse("https://example.com/article/42"))
))
Damit fließt die Idee aus den Android Testing Fundamentals direkt in deinen Continuous-Integration-Workflow ein: Jeder Pull Request kann verifizieren, dass das Teilen, Öffnen oder Anrufen weiterhin korrekt funktioniert. Solche Tests sind günstig, schnell und schützen dich vor stillen Regressionen, wenn du später Refactorings durchführst.
Fazit
Intents sind kein Beiwerk, sondern das Rückgrat der Android-Kommunikation. Wenn du den Unterschied zwischen explizit und implizit, die Rolle der Action und die typischen Stolperfallen verstanden hast, baust du robustere Apps, die sich sauber in das System einfügen. Öffne jetzt dein aktuelles Projekt und suche nach jedem startActivity-Aufruf. Stelle dir bei jedem Treffer dieselbe Frage: Adressiere ich hier eine konkrete Komponente oder formuliere ich eine Absicht? Schreibe danach einen Espresso-Test, der genau diesen Intent verifiziert, und prüfe im Manifest, ob deine eigenen Intent-Filter wirklich nur das nach außen öffnen, was du teilen willst. Erst wenn dein Test grün ist und das Manifest sauber, hast du das Konzept tatsächlich in der Hand.