ActivityResultLauncher är en komponent i Android Activity Result API, introducerad i version Activity 1.2.0 av androidx.activity-biblioteket. Den ersätter de föråldrade metoderna startActivityForResult och onActivityResult, som har varit en del av Android SDK sedan dess skapelse. Enligt Android Developers (2024) eliminerar det nya API:et problemen med tät koppling till Activity och bristen på typsäkerhet. ActivityResultLauncher registreras i förväg och använder Contract för strikt typning av in- och utdata.
Huvudpunkter
ActivityResultLauncher är en klass från paketet androidx.activity.result som tillhandahåller en typsäker mekanism för att starta Activity och ta emot resultatet. Launcher skapas via metoden registerForActivityResult, som tar två parametrar: Contract (beskriver in- och utdatatyper) och ActivityResultCallback (resultathanteraren). Efter registrering är launcher redo för anrop via metoden launch.
Den viktigaste skillnaden jämfört med det gamla API:et är separationen av registrering och start. Registrering sker i initieringsfasen (Activity.onCreate eller Fragment.onCreate), callback kopplas till launcher en gång och garanteras aktiveras när resultatet returneras. Detta eliminerar problemet när onActivityResult aktiverades i oväntad ordning eller på en förstörd Activity.
ActivityResultLauncher stöder alla scenarier som tidigare hanterades via onActivityResult: starta kamera, galleri, begära kontakter, behörigheter och anpassade Activity. Dessutom är API:et utbyggbart: utvecklaren kan skapa egna Contract för specifika scenarier för datautbyte mellan Activity.
startActivityForResult har varit en del av Android SDK sedan version API Level 1 (2008) och förblev det främsta sättet att få resultat från Activity i över 12 år. Men denna metod hade grundläggande brister som Google åtgärdade i Activity Result API. Låt oss titta på de viktigaste problemen och hur det nya API:et löser dem.
Metoden startActivityForResult är kopplad till Activity och Fragment via requestCode — ett godtyckligt heltal som skickas till onActivityResult. Utvecklaren matchade manuellt koden med den startade operationen, vilket ledde till fel vid återanvändning av kod och arv. ActivityResultLauncher eliminerar requestCode helt: callback kopplas till en specifik launcher i registreringsfasen och anropas endast för den.
Vid konfigurationsändringar (skärmrotation, språkbyte) återskapades Activity och onActivityResult kunde inte aktiveras — callback gick förlorad. Activity Result API sparar och återställer automatiskt launchens tillstånd via SavedStateRegistry, vilket garanterar att resultatet tas emot även efter återskapande av Activity.
Det gamla API:et överförde resultatet via Intent med Bundle, där nycklar och datatyper inte kontrollerades av kompilatorn. Activity Result API använder Contract — ett generiskt gränssnitt som definierar typen av indata (I) och typen av resultat (O). Typfel upptäcks i kompileringsfasen, inte vid körning.
| Egenskap | startActivityForResult | ActivityResultLauncher |
|---|---|---|
| RequestCode | Kräver manuell hantering | Automatisk, krävs inte |
| Typsäkerhet | Nej | Generic Contract |
| Bevarande vid rotation | Förloras | SavedStateRegistry |
| Minsta API | API Level 1 | Activity 1.2.0 |
| Användning i Compose | Stöds inte | rememberLauncherForActivityResult |
Contract är ett gränssnitt ActivityResultContract<I, O> som definierar hur Activity ska startas och hur resultatet ska tolkas. Google tillhandahåller en uppsättning inbyggda kontrakt för typiska scenarier som täcker de flesta utvecklarbehov.
StartIntentSenderForResult är grundkontraktet för att starta IntentSender. Används i systemscenarier, till exempel vid autentisering via Google Sign-In eller betalning via Google Pay. Indataparameter — PendingIntent, utdata — ActivityResult med kod och Intent.
RequestMultiplePermissions är kontraktet för att begära flera behörigheter samtidigt i Android 6.0+. Indataparameter — en String-array med behörighetsnamn, utdata — Map<String, Boolean> med resultatet av varje begäran. Tidigare krävde detta manuell tolkning i onRequestPermissionsResult med matchning av begärandekoder.
TakePicture är kontraktet för att ta foto via systemkameran. Indata — Uri där fotot sparas, utdata — Boolean (framgång). TakeVideo fungerar på liknande sätt med video. Dessa kontrakt ersätter den föråldrade MediaStore.ACTION_IMAGE_CAPTURE med instabilt beteende på olika enheter.
GetContent är kontraktet för att välja innehåll via systemväljaren. Indata — MIME-typ (t.ex. image/*), utdata — Uri för den valda filen. OpenDocument skiljer sig genom stöd för flerval och filtrering efter dokumenttyper. Båda kontrakten fungerar via SAF (Storage Access Framework).
CreateDocument är kontraktet för att skapa ett nytt dokument via systemdialogrutan. Användaren väljer namn och mapp, systemet returnerar Uri för skrivning. OpenDocumentTree ger åtkomst till en hel katalog — användaren väljer en mapp och applikationen får tree-uri för att läsa och skriva alla filer inuti.
Grundmönstret för att använda ActivityResultLauncher i klassisk Android består av två steg: registrering via registerForActivityResult i initieringsfasen och anrop av launch som svar på en användaråtgärd. Låt oss titta på ett typiskt exempel på att välja en bild från galleriet.
Registrera launchern i Activitys onCreate — detta garanterar att callback är redo före varje möjligt anrop. Registrera aldrig launchern omedelbart före start — detta bryter mot API-kontraktet och kan leda till förlust av resultat vid återskapande av Activity.
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/*")
}
}
I Fragment sker registrering i onCreate, onAttach eller initiering i onCreateView. FragmentActivity skickar launchern via den överordnade Activity, så resultatet bearbetas inuti Fragment, inte i Activity. Detta förbättrar inkapslingen jämfört med onActivityResult, där alla resultat från alla Fragment samlades i en enda metod i Activity.
class ProfileFragment : Fragment() {
private val cameraLauncher =
registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
if (success) { updateProfilePhoto() }
}
fun takePhoto(photoUri: Uri) {
cameraLauncher.launch(photoUri)
}
}
Jetpack Compose tillhandahåller speciell composable-funktionalitet för Activity Result API — rememberLauncherForActivityResult. Till skillnad från den klassiska metoden skapas launchern i Compose som ett objekt kopplat till composablens livscykel via remember. Detta gör det möjligt att använda Activity Result API helt deklarativt utan direkt åtkomst till Activity eller Fragment.
rememberLauncherForActivityResult tar emot Contract och callback och returnerar ActivityResultLauncher. Launchern bevaras vid rekomposition och rensas automatiskt vid utträde ur kompositionen. Anropet launch sker som svar på en händelse — till exempel knapptryckning eller statusändring.
@Composable
fun PhotoPicker() {
val context = LocalContext.current
val launcher = rememberLauncherForActivityResult(
ActivityResultContracts.GetContent()
) { uri -> handleImage(uri) }
Button(onClick = { launcher.launch("image/*") }) {
Text("Välj foto")
}
}
Begäran om behörigheter i Compose görs också via rememberLauncherForActivityResult med kontraktet RequestPermission eller RequestMultiplePermissions. Google rekommenderar att använda accompanist-permissions, men under huven använder det också Activity Result API. För att kontrollera behörighetsstatus är det bekvämt att lagra status i remember eller ViewModel.
Activity Result API har eliminerat många problem med den gamla metoden, men felaktig användning kan leda till nya typer av fel. Låt oss titta på de vanligaste problemen och hur man undviker dem.
Registrering av launchern måste ske vid initiering av komponenten — i Activitys onCreate eller Fragments initierare. Om du registrerar launchern inuti en lambda, callback eller korutin, kan registreringen utföras igen när Activity återskapas och den gamla launchern förlorar kopplingen till resultatet.
Varje launcher får en unik nyckel för att spara tillstånd. Om du registrerar två launchers med samma Contract i en komponent kan SavedStateRegistry skriva över den enas tillstånd med den andras. Android Studio varnar om detta via lint-regeln UnnecessaryRegisterForActivityResult, men det är bättre att kontrollera unikheten manuellt.
Användaren kan avbryta åtgärden — trycka på systemets bakåtknapp, minimera appen eller byta till en annan app. I detta fall kommer callback att få null eller ActivityResult med RESULT_CANCELED. Kontrollera alltid resultatet för null före användning för att undvika NullPointerException.
Om din app ofta startar liknande scenarier — till exempel att välja en kontakt med returnering av namn och telefon — skapa ditt eget Contract. Detta förbättrar kodens läsbarhet och möjliggör centraliserad ändring av logiken för start och resultathantering.
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) }
}
Vanliga frågor
Nej — ActivityResultLauncher kräver Activity- eller Fragment-kontext för registrering. Använd ViewModel endast för att lagra tillstånd och skapa launchern i Activity eller Fragment och skicka resultatet till ViewModel.
Activity Result API är tillgängligt från biblioteket activity-ktx 1.2.0. Minsta SDK — API Level 14 (Android 4.0), men de flesta kontrakt fungerar endast på API Level 19+.
Upprepat anrop av launch före slutförandet av den första operationen kommer att ignoreras. Activity Result API stöder inte parallella starter — vänta på callback från den första operationen före ett nytt anrop.
Migrering görs genom att ersätta anropet startActivityForResult med registerForActivityResult med motsvarande Contract. Ta bort onActivityResult och hantera resultatet i launcherns callback. Google tillhandahåller en migreringsguide i Android Developers-dokumentationen.
Ja, många bibliotek stöder integration via ActivityResultContracts. Till exempel använder ML Kit Barcode Scanner StartIntentSenderForResult för att starta skannern. Kontrollera dokumentationen för det specifika biblioteket.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också