ActivityResultLauncher: ce este și cum să folosești

Autor: IT Sectr Publicat: 2026-06-10 Timp de citire: 9 min

ActivityResultLauncher este o componentă a Android Activity Result API, introdusă în versiunea Activity 1.2.0 a bibliotecii androidx.activity. Acesta înlocuiește metodele învechite startActivityForResult și onActivityResult, care făceau parte din Android SDK de la crearea sa. Potrivit Android Developers (2024), noul API elimină problemele de cuplare strânsă cu Activity și lipsa siguranței tipurilor. ActivityResultLauncher se înregistrează în avans și folosește Contract pentru tipizarea strictă a datelor de intrare și ieșire.

Principalele

  • ActivityResultLauncher — noul API pentru obținerea rezultatului de la Activity în locul învechitului startActivityForResult
  • Contract — obiectul care definește tipul datelor de intrare și ieșire pentru un scenariu specific
  • Înregistrarea se face prin registerForActivityResult înainte de apelul launch
  • Callback — este apelat după finalizarea Activity țintă cu rezultatul
  • API disponibil pentru Activity, Fragment și Compose începând cu Activity 1.2.0

Ce este ActivityResultLauncher

ActivityResultLauncher este o clasă din pachetul androidx.activity.result, care oferă un mecanism sigur din punct de vedere al tipurilor pentru lansarea Activity și obținerea rezultatului. Launcher este creat prin metoda registerForActivityResult, care primește doi parametri: Contract (descrie tipurile de intrare și ieșire) și ActivityResultCallback (handlerul rezultatului). După înregistrare, launcher este gata pentru apel prin metoda launch.

Diferența cheie față de API-ul vechi — separarea înregistrării și lansării. Înregistrarea se face în etapa de inițializare (Activity.onCreate sau Fragment.onCreate), callback-ul este legat de launcher o singură dată și este garantat să se declanșeze la returnarea rezultatului. Aceasta elimină problema când onActivityResult se declanșa într-o ordine neașteptată sau pe un Activity distrus.

ActivityResultLauncher suportă toate scenariile care erau gestionate anterior prin onActivityResult: lansarea camerei, galeriei, solicitarea contactelor, permisiunilor și Activity-urilor personalizate. În plus, API-ul este extensibil: dezvoltatorul poate crea Contract-uri personalizate pentru scenarii specifice de schimb de date între Activity-uri.

De ce Activity Result API a înlocuit startActivityForResult

startActivityForResult a fost parte din Android SDK de la versiunea API Level 1 (2008) și a rămas principala modalitate de a obține rezultatul de la Activity timp de peste 12 ani. Cu toate acestea, această metodă avea defecte fundamentale pe care Google le-a eliminat în Activity Result API. Să analizăm problemele principale și cum le rezolvă noul API.

Problema 1: cuplarea strânsă cu Activity

Metoda startActivityForResult este legată de Activity și Fragment prin requestCode — un număr întreg arbitrar care este transmis în onActivityResult. Dezvoltatorul potrivea manual codul cu operația lansată, ceea ce ducea la erori la reutilizarea codului și moștenire. ActivityResultLauncher elimină complet requestCode: callback-ul este legat de un anumit launcher în etapa de înregistrare și este apelat doar pentru acesta.

Problema 2: pierderea rezultatului la rotirea ecranului

La modificări de configurare (rotirea ecranului, schimbarea limbii) Activity era recreat, iar onActivityResult putea să nu se declanșeze — callback-ul se pierdea. Activity Result API salvează și restaurează automat starea launcher-ului prin SavedStateRegistry, ceea ce garantează primirea rezultatului chiar și după recrearea Activity.

Problema 3: lipsa siguranței tipurilor

API-ul vechi transmitea rezultatul prin Intent cu Bundle, unde cheile și tipurile de date nu erau verificate de compilator. Activity Result API folosește Contract — o interfață generică care definește tipul datelor de intrare (I) și tipul rezultatului (O). Erorile de nepotrivire a tipurilor sunt detectate în faza de compilare, nu la runtime.

CaracteristicăstartActivityForResultActivityResultLauncher
RequestCodeNecesită gestionare manualăAutomat, nu este necesar
Siguranța tipurilorNuGeneric Contract
Salvare la rotireSe pierdeSavedStateRegistry
API minimAPI Level 1Activity 1.2.0
Utilizare în ComposeNu este suportatrememberLauncherForActivityResult

Principalele contracte Activity Result API

Contract — este o interfață ActivityResultContract<I, O>, care definește cum să lanseze Activity și cum să interpreteze rezultatul. Google oferă un set de contracte încorporate pentru scenarii tipice, acoperind majoritatea nevoilor dezvoltatorului.

StartIntentSenderForResult

StartIntentSenderForResult — contractul de bază pentru lansarea IntentSender. Folosit în scenarii de sistem, de exemplu la autentificarea prin Google Sign-In sau la plata prin Google Pay. Parametrul de intrare — PendingIntent, ieșire — ActivityResult cu cod și Intent.

RequestMultiplePermissions

RequestMultiplePermissions — contractul pentru solicitarea mai multor permisiuni simultan în Android 6.0+. Parametrul de intrare — un array String cu numele permisiunilor, ieșire — Map<String, Boolean> cu rezultatul fiecărei solicitări. Anterior, acest lucru necesita parsare manuală în onRequestPermissionsResult cu potrivirea codurilor de solicitare.

TakePicture și TakeVideo

TakePicture — contractul pentru fotografierea prin camera sistem. Intrare — Uri unde se salvează fotografia, ieșire — Boolean (succes). TakeVideo funcționează similar cu video. Aceste contracte înlocuiesc învechitul MediaStore.ACTION_IMAGE_CAPTURE cu comportament instabil pe diferite dispozitive.

GetContent și OpenDocument

GetContent — contractul pentru selectarea conținutului prin selectorul de sistem. Intrare — tip MIME (de exemplu image/*), ieșire — Uri al fișierului selectat. OpenDocument se diferențiază prin suport pentru selecție multiplă și filtrare după tipurile de documente. Ambele contracte funcționează prin SAF (Storage Access Framework).

CreateDocument și OpenDocumentTree

CreateDocument — contractul pentru crearea unui document nou prin dialogul de sistem. Utilizatorul alege numele și folderul, sistemul returnează Uri pentru scriere. OpenDocumentTree oferă acces la întregul director — utilizatorul alege un folder, iar aplicația primește tree-uri pentru citirea și scrierea tuturor fișierelor din interior.

Utilizarea în Activity și Fragment

Modelul de bază de utilizare a ActivityResultLauncher în Android clasic constă din doi pași: înregistrarea prin registerForActivityResult în etapa de inițializare și apelul launch ca răspuns la acțiunea utilizatorului. Să analizăm un exemplu tipic de selectare a unei imagini din galerie.

Înregistrarea și lansarea în Activity

Înregistrați launcher-ul în onCreate al Activity — aceasta garantează că callback-ul va fi gata înainte de orice apel posibil. Nu înregistrați niciodată launcher-ul imediat înainte de lansare — aceasta încalcă contractul API și poate duce la pierderea rezultatului la recrearea Activity.

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/*")
    }
}

Utilizarea în Fragment

În Fragment înregistrarea se face în onCreate, onAttach sau inițializare în onCreateView. FragmentActivity transmite launcher-ul prin Activity-ul părinte, astfel încât rezultatul este gestionat în interiorul Fragment, nu în Activity. Aceasta îmbunătățește încapsularea comparativ cu onActivityResult, unde toate rezultatele din toate Fragment-urile erau colectate într-o singură metodă a Activity.

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

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

ActivityResultLauncher în Jetpack Compose

Jetpack Compose oferă o funcționalitate composable specială pentru Activity Result API — rememberLauncherForActivityResult. Spre deosebire de abordarea clasică, în Compose launcher-ul este creat ca un obiect legat de ciclul de viață al composable-ului prin remember. Acest lucru permite utilizarea Activity Result API în stil complet declarativ fără acces direct la Activity sau Fragment.

rememberLauncherForActivityResult

rememberLauncherForActivityResult primește Contract și callback, returnând ActivityResultLauncher. Launcher-ul este păstrat la recompoziție și este curățat automat la ieșirea din compoziție. Apelul launch are loc ca răspuns la un eveniment — de exemplu, apăsarea unui buton sau schimbarea stării.

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

    Button(onClick = { launcher.launch("image/*") }) {
        Text("Alege fotografie")
    }
}

Gestionarea permisiunilor în Compose

Solicitarea permisiunilor în Compose se face, de asemenea, prin rememberLauncherForActivityResult cu contractul RequestPermission sau RequestMultiplePermissions. Google recomandă utilizarea accompanist-permissions, dar în spate folosește tot Activity Result API. Pentru controlul stării permisiunilor, este convenabil să stocați starea în remember sau ViewModel.

Erori tipice și cele mai bune practici

Activity Result API a eliminat multe probleme ale abordării vechi, dar utilizarea sa incorectă poate duce la noi tipuri de erori. Să analizăm cele mai frecvente probleme și modalitățile de a le evita.

Eroare: înregistrarea în interiorul unei lambda sau corutine

Înregistrarea launcher-ului trebuie să aibă loc la inițializarea componentului — în onCreate al Activity sau inițializatorul Fragment. Dacă înregistrați launcher-ul în interiorul unei lambda, callback sau corutine, la recrearea Activity înregistrarea poate fi efectuată din nou, iar launcher-ul vechi va pierde legătura cu rezultatul.

Eroare: înregistrarea mai multor launcher-uri cu aceeași cheie

Fiecare launcher primește o cheie unică pentru salvarea stării. Dacă înregistrați două launcher-uri cu același Contract într-un singur component, SavedStateRegistry poate suprascrie starea unuia peste celălalt. Android Studio avertizează despre acest lucru prin regula lint UnnecessaryRegisterForActivityResult, dar este mai bine să controlați unicitatea manual.

Bună practică: gestionați întotdeauna rezultatul null

Utilizatorul poate anula acțiunea — apăsa butonul de înapoi al sistemului, minimiza aplicația sau comuta la o altă aplicație. În acest caz, callback-ul va primi null sau ActivityResult cu RESULT_CANCELED. Verificați întotdeauna rezultatul pentru null înainte de utilizare pentru a evita NullPointerException.

Bună practică: Contract-uri personalizate pentru logică reutilizabilă

Dacă aplicația dvs. lansează frecvent scenarii similare — de exemplu, selectarea unui contact cu returnarea numelui și telefonului — creați propriul Contract. Aceasta îmbunătățește lizibilitatea codului și permite modificarea centralizată a logicii de lansare și gestionare a rezultatului.

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) }
}

Întrebări frecvente

Se poate folosi ActivityResultLauncher în ViewModel?

Nu — ActivityResultLauncher necesită context de Activity sau Fragment pentru înregistrare. Folosiți ViewModel doar pentru stocarea stării, iar launcher-ul creați-l în Activity sau Fragment și transmiteți rezultatul în ViewModel.

Care este SDK-ul minim necesar pentru Activity Result API?

Activity Result API este disponibil începând cu biblioteca activity-ktx 1.2.0. SDK minim — API Level 14 (Android 4.0), dar majoritatea contractelor funcționează doar pe API Level 19+.

Ce se întâmplă dacă launch este apelat de două ori înainte de primirea rezultatului?

Apelul repetat al launch înainte de finalizarea primei operații va fi ignorat. Activity Result API nu suportă lansări paralele — așteptați callback-ul de la prima operație înainte de un nou apel.

Cu ce să înlocuiesc onActivityResult în codul vechi?

Migrarea se face prin înlocuirea apelului startActivityForResult cu registerForActivityResult cu Contract-ul corespunzător. Ștergeți onActivityResult și gestionați rezultatul în callback-ul launcher-ului. Google oferă un ghid de migrare în documentația Android Developers.

Funcționează ActivityResultLauncher cu biblioteci precum ML Kit sau Barcode Scanner?

Da, multe biblioteci suportă integrarea prin ActivityResultContracts. De exemplu, ML Kit Barcode Scanner folosește StartIntentSenderForResult pentru lansarea scanerului. Verificați documentația bibliotecii specifice.

Concluzii

  • ActivityResultLauncher — API modern sigur din punct de vedere al tipurilor în locul învechitului startActivityForResult
  • Contract definește tipul datelor de intrare și ieșire, eliminând potrivirea manuală a requestCode-ului
  • Înregistrarea se face în etapa de inițializare, rezultatul este garantat livrat prin callback
  • Contractele încorporate acoperă camera, galeria, permisiunile, documentele și contactele
  • Jetpack Compose folosește rememberLauncherForActivityResult pentru lucrul cu API-ul
  • Contract-urile personalizate permit reutilizarea logicii de lansare între componente
  • API-ul salvează starea la modificări de configurare prin SavedStateRegistry

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și