ActivityResultLauncher: Was es ist und wie man es verwendet

Autor: IT Sectr Veröffentlicht: 2026-06-10 Lesezeit: 9 Min.

ActivityResultLauncher ist eine Komponente der Android Activity Result API, die in Version Activity 1.2.0 der Bibliothek androidx.activity eingeführt wurde. Es ersetzt die veralteten Methoden startActivityForResult und onActivityResult, die seit der Gründung des Android SDK Teil davon waren. Laut Android Developers (2024) beseitigt die neue API die Probleme der engen Kopplung mit Activity und der fehlenden Typsicherheit. ActivityResultLauncher wird im Voraus registriert und verwendet einen Contract für die strenge Typisierung von Eingabe- und Ausgabedaten.

Wichtige Punkte

  • ActivityResultLauncher — eine neue API zum Erhalten von Ergebnissen von einer Activity anstelle des veralteten startActivityForResult
  • Contract — ein Objekt, das den Typ der Eingabe- und Ausgabedaten für ein bestimmtes Szenario definiert
  • Registrierung erfolgt über registerForActivityResult vor dem Aufruf von launch
  • Callback wird aufgerufen, nachdem die Ziel-Activity mit einem Ergebnis abgeschlossen wurde
  • API verfügbar für Activity, Fragment und Compose ab Activity 1.2.0

Was ist ActivityResultLauncher

ActivityResultLauncher ist eine Klasse aus dem Paket androidx.activity.result, die einen typsicheren Mechanismus zum Starten einer Activity und zum Empfangen eines Ergebnisses bereitstellt. Der Launcher wird über die Methode registerForActivityResult erstellt, die zwei Parameter akzeptiert: Contract (beschreibt Eingabe- und Ausgabetypen) und ActivityResultCallback (Ergebnis-Handler). Nach der Registrierung ist der Launcher bereit, über die Methode launch aufgerufen zu werden.

Der Hauptunterschied zur alten API ist die Trennung von Registrierung und Start. Die Registrierung erfolgt in der Initialisierungsphase (Activity.onCreate oder Fragment.onCreate), der Callback wird einmal an den Launcher gebunden und wird garantiert ausgeführt, wenn das Ergebnis zurückkommt. Dies beseitigt das Problem, dass onActivityResult in einer unerwarteten Reihenfolge oder auf einer zerstörten Activity ausgelöst wurde.

ActivityResultLauncher unterstützt alle Szenarien, die zuvor über onActivityResult behandelt wurden: Kamera starten, Galerie, Kontakte anfordern, Berechtigungen und benutzerdefinierte Activities. Darüber hinaus ist die API erweiterbar: Entwickler können benutzerdefinierte Contracts für spezifische Datenaustauschszenarien zwischen Activities erstellen.

Warum Activity Result API startActivityForResult ersetzt hat

startActivityForResult war seit API Level 1 (2008) Teil des Android SDK und blieb über 12 Jahre lang die primäre Methode, um ein Ergebnis von einer Activity zu erhalten. Diese Methode hatte jedoch grundlegende Mängel, die Google in der Activity Result API behoben hat. Schauen wir uns die Hauptprobleme an und wie die neue API sie löst.

Problem 1: Enge Kopplung mit Activity

Die Methode startActivityForResult ist über requestCode an Activity und Fragment gebunden — eine beliebige ganze Zahl, die an onActivityResult übergeben wird. Der Entwickler musste den Code manuell mit der gestarteten Operation abgleichen, was zu Fehlern bei der Wiederverwendung von Code und Vererbung führte. ActivityResultLauncher eliminiert requestCode vollständig: Der Callback wird bei der Registrierung an einen bestimmten Launcher gebunden und nur für diesen aufgerufen.

Problem 2: Ergebnisverlust bei Bildschirmdrehung

Bei Konfigurationsänderungen (Bildschirmdrehung, Sprachwechsel) wurde die Activity neu erstellt und onActivityResult konnte fehlschlagen — der Callback ging verloren. Die Activity Result API speichert und stellt den Launcher-Zustand automatisch über SavedStateRegistry wieder her, sodass das Ergebnis auch nach der Neuerstellung der Activity garantiert empfangen wird.

Problem 3: Fehlende Typsicherheit

Die alte API übergab das Ergebnis über Intent mit einem Bundle, wobei Schlüssel und Datentypen nicht vom Compiler überprüft wurden. Die Activity Result API verwendet Contract — eine generische Schnittstelle, die den Eingabedatentyp (I) und den Ergebnistyp (O) definiert. Typinkompatibilitätsfehler werden zur Compile-Zeit erkannt, nicht zur Laufzeit.

MerkmalstartActivityForResultActivityResultLauncher
RequestCodeManuelle Verwaltung erforderlichAutomatisch, nicht erforderlich
TypsicherheitNeinGenerischer Contract
Speichern bei DrehungVerlorenSavedStateRegistry
Minimale APIAPI Level 1Activity 1.2.0
Verwendung in ComposeNicht unterstütztrememberLauncherForActivityResult

Wichtigste Verträge der Activity Result API

Contract ist das Interface ActivityResultContract<I, O>, das definiert, wie eine Activity gestartet und wie das Ergebnis interpretiert wird. Google bietet eine Reihe integrierter Verträge für typische Szenarien, die die meisten Entwickleranforderungen abdecken.

StartIntentSenderForResult

StartIntentSenderForResult — ein grundlegender Vertrag zum Starten von IntentSender. Wird in Systemszenarien verwendet, z. B. bei der Autorisierung über Google Sign-In oder bei Zahlungen über Google Pay. Der Eingabeparameter ist PendingIntent, die Ausgabe ist ActivityResult mit Code und Intent.

RequestMultiplePermissions

RequestMultiplePermissions — ein Vertrag zum gleichzeitigen Anfordern mehrerer Berechtigungen unter Android 6.0+. Der Eingabeparameter ist ein String-Array mit Berechtigungsnamen, die Ausgabe ist Map<String, Boolean> mit dem Ergebnis jeder Anfrage. Früher erforderte dies manuelles Parsen in onRequestPermissionsResult mit Abgleich der Anforderungscodes.

TakePicture und TakeVideo

TakePicture — ein Vertrag zum Aufnehmen eines Fotos über die Systemkamera. Die Eingabe ist ein Uri zum Speichern des Bildes, die Ausgabe ist Boolean (Erfolg). TakeVideo funktioniert ähnlich mit Video. Diese Verträge ersetzen das veraltete MediaStore.ACTION_IMAGE_CAPTURE mit instabilem Verhalten auf verschiedenen Geräten.

GetContent und OpenDocument

GetContent — ein Vertrag zum Auswählen von Inhalten über die Systemauswahl. Die Eingabe ist ein MIME-Typ (z. B. image/*), die Ausgabe ist ein Uri der ausgewählten Datei. OpenDocument unterscheidet sich durch die Unterstützung von Mehrfachauswahl und Filterung nach Dokumenttypen. Beide Verträge funktionieren über SAF (Storage Access Framework).

CreateDocument und OpenDocumentTree

CreateDocument — ein Vertrag zum Erstellen eines neuen Dokuments über den Systemdialog. Der Benutzer wählt einen Namen und Ordner, das System gibt einen Uri zum Schreiben zurück. OpenDocumentTree bietet Zugriff auf ein gesamtes Verzeichnis — der Benutzer wählt einen Ordner und die App erhält einen tree-uri zum Lesen und Schreiben aller darin enthaltenen Dateien.

Verwendung in Activity und Fragment

Das grundlegende Muster zur Verwendung von ActivityResultLauncher in klassischem Android besteht aus zwei Schritten: Registrierung über registerForActivityResult bei der Initialisierung und Aufruf von launch als Reaktion auf eine Benutzeraktion. Schauen wir uns ein typisches Beispiel zum Auswählen eines Bildes aus der Galerie an.

Registrierung und Start in Activity

Registrieren Sie den Launcher im onCreate der Activity — dies stellt sicher, dass der Callback vor jedem möglichen Aufruf bereit ist. Registrieren Sie einen Launcher niemals unmittelbar vor dem Start — dies verstößt gegen den API-Vertrag und kann bei der Neuerstellung der Activity zum Verlust des Ergebnisses führen.

kotlin
class MainActivity : AppCompatActivity() {
    private val pickImageLauncher =
        registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
            uri?.let { binding.imageView.setImageURI(it) }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        pickImageLauncher.launch("image/*")
    }
}

Verwendung in Fragment

In einem Fragment erfolgt die Registrierung in onCreate, onAttach oder in der Initialisierung in onCreateView. FragmentActivity übergibt den Launcher über die Eltern-Activity, sodass das Ergebnis innerhalb des Fragments verarbeitet wird, nicht in der Activity. Dies verbessert die Kapselung im Vergleich zu onActivityResult, wo alle Ergebnisse aller Fragments in einer einzigen Activity-Methode gesammelt wurden.

kotlin
class ProfileFragment : Fragment() {
    private val cameraLauncher =
        registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
            if (success) { updateProfilePhoto() }
        }

    fun takePhoto(photoUri: Uri) {
        cameraLauncher.launch(photoUri)
    }
}

ActivityResultLauncher in Jetpack Compose

Jetpack Compose bietet eine spezielle composable-Funktion für die Activity Result API — rememberLauncherForActivityResult. Im Gegensatz zum klassischen Ansatz wird der Launcher in Compose als Objekt erstellt, das über remember an den Lebenszyklus des Composables gebunden ist. Dies ermöglicht die Verwendung der Activity Result API vollständig in einem deklarativen Stil ohne direkten Zugriff auf Activity oder Fragment.

rememberLauncherForActivityResult

rememberLauncherForActivityResult nimmt einen Contract und einen Callback entgegen und gibt einen ActivityResultLauncher zurück. Der Launcher bleibt während der Rekomposition erhalten und wird beim Verlassen der Komposition automatisch gelöscht. Der launch-Aufruf erfolgt als Reaktion auf ein Ereignis — beispielsweise einen Button-Klick oder eine Zustandsänderung.

kotlin
@Composable
fun PhotoPicker() {
    val context = LocalContext.current
    val launcher = rememberLauncherForActivityResult(
        ActivityResultContracts.GetContent()
    ) { uri -> handleImage(uri) }

    Button(onClick = { launcher.launch("image/*") }) {
        Text("Foto auswählen")
    }
}

Berechtigungsverwaltung in Compose

Berechtigungsanfragen in Compose werden ebenfalls über rememberLauncherForActivityResult mit dem Contract RequestPermission oder RequestMultiplePermissions durchgeführt. Google empfiehlt die Verwendung von accompanist-permissions, aber intern verwendet es ebenfalls die Activity Result API. Zur Verfolgung des Berechtigungsstatus ist es praktisch, den Status in remember oder ViewModel zu speichern.

Häufige Fehler und Best Practices

Die Activity Result API hat viele Probleme des alten Ansatzes beseitigt, aber eine unsachgemäße Verwendung kann zu neuen Arten von Fehlern führen. Schauen wir uns die häufigsten Probleme an und wie man sie vermeidet.

Fehler: Registrierung innerhalb eines Lambda oder einer Coroutine

Die Registrierung des Launchers muss während der Komponenteninitialisierung erfolgen — im onCreate der Activity oder im Fragment-Initialisierer. Wenn Sie den Launcher innerhalb eines Lambda, Callbacks oder einer Coroutine registrieren, kann die Registrierung bei der Neuerstellung der Activity erneut durchgeführt werden und der alte Launcher verliert die Verbindung zum Ergebnis.

Fehler: Registrieren mehrerer Launcher mit demselben Schlüssel

Jeder Launcher erhält einen eindeutigen Schlüssel zum Speichern des Zustands. Wenn Sie zwei Launcher mit demselben Contract in einer Komponente registrieren, kann SavedStateRegistry den Zustand des einen mit dem des anderen überschreiben. Android Studio warnt davor über die Lint-Regel UnnecessaryRegisterForActivityResult, aber es ist besser, die Eindeutigkeit manuell zu kontrollieren.

Best Practice: Immer Null-Ergebnis behandeln

Der Benutzer kann die Aktion abbrechen — die System-Zurück-Taste drücken, die App minimieren oder zu einer anderen App wechseln. In diesem Fall erhält der Callback null oder ActivityResult mit RESULT_CANCELED. Überprüfen Sie das Ergebnis immer auf null, bevor Sie es verwenden, um NullPointerException zu vermeiden.

Best Practice: Benutzerdefinierte Contracts für wiederverwendbare Logik

Wenn Ihre App häufig ähnliche Szenarien startet — z. B. einen Kontakt auswählen und Namen und Telefonnummer zurückgeben — erstellen Sie einen benutzerdefinierten Contract. Dies verbessert die Lesbarkeit des Codes und ermöglicht zentrale Änderungen an der Start- und Ergebnisverarbeitungslogik.

kotlin
class PickContactContract : ActivityResultContract<Void, ContactData?>() {
    override fun createIntent(context: Context, input: Void?) =
        Intent(Intent.ACTION_PICK).setType(ContactsContract.Contacts.CONTENT_TYPE)

    override fun parseResult(resultCode: Int, intent: Intent?) =
        intent?.data?.let { queryContact(it) }
}

Häufig gestellte Fragen

Kann ActivityResultLauncher im ViewModel verwendet werden?

Nein — ActivityResultLauncher benötigt einen Activity- oder Fragment-Kontext zur Registrierung. Verwenden Sie ViewModel nur zum Speichern von Zuständen und erstellen Sie den Launcher in der Activity oder im Fragment und übergeben Sie das Ergebnis an das ViewModel.

Welches minimale SDK wird für die Activity Result API benötigt?

Activity Result API ist ab der Bibliothek activity-ktx 1.2.0 verfügbar. Das minimale SDK ist API Level 14 (Android 4.0), aber die meisten Verträge funktionieren nur ab API Level 19+.

Was passiert, wenn launch zweimal aufgerufen wird, bevor ein Ergebnis eingeht?

Ein wiederholter Aufruf von launch vor Abschluss des ersten Vorgangs wird ignoriert. Die Activity Result API unterstützt keine parallelen Starts — warten Sie auf den Callback des ersten Vorgangs, bevor Sie einen neuen Aufruf tätigen.

Wie ersetzt man onActivityResult in altem Code?

Die Migration erfolgt durch Ersetzen des startActivityForResult-Aufrufs durch registerForActivityResult mit dem entsprechenden Contract. Entfernen Sie onActivityResult und behandeln Sie das Ergebnis im Launcher-Callback. Google stellt einen Migrationsleitfaden in der Android Developers-Dokumentation bereit.

Funktioniert ActivityResultLauncher mit Bibliotheken wie ML Kit oder Barcode Scanner?

Ja, viele Bibliotheken unterstützen die Integration über ActivityResultContracts. Beispielsweise verwendet ML Kit Barcode Scanner StartIntentSenderForResult zum Starten des Scanners. Prüfen Sie die Dokumentation der jeweiligen Bibliothek.

Zusammenfassung

  • ActivityResultLauncher — eine moderne typsichere API, die das veraltete startActivityForResult ersetzt
  • Contract definiert die Eingabe- und Ausgabedatentypen und eliminiert den manuellen requestCode-Abgleich
  • Registrierung erfolgt bei der Initialisierung, das Ergebnis wird garantiert über Callback zugestellt
  • Integrierte Verträge decken Kamera, Galerie, Berechtigungen, Dokumente und Kontakte ab
  • Jetpack Compose verwendet rememberLauncherForActivityResult zur Arbeit mit der API
  • Benutzerdefinierte Contracts ermöglichen die Wiederverwendung von Startlogik zwischen Komponenten
  • API bewahrt Zustand bei Konfigurationsänderungen über SavedStateRegistry

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch