ActivityResultLauncher: τι είναι και πώς να το χρησιμοποιήσετε

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-06-10 Χρόνος ανάγνωσης: 9 λεπ

Το ActivityResultLauncher είναι ένα στοιχείο του Android Activity Result API, που παρουσιάστηκε στην έκδοση Activity 1.2.0 της βιβλιοθήκης androidx.activity. Αντικαθιστά τις ξεπερασμένες μεθόδους startActivityForResult και onActivityResult, οι οποίες αποτελούσαν μέρος του Android SDK από τη δημιουργία του. Σύμφωνα με το Android Developers (2024), το νέο API εξαλείφει τα προβλήματα της στενής σύνδεσης με το Activity και της έλλειψης ασφάλειας τύπων. Το ActivityResultLauncher καταχωρείται εκ των προτέρων και χρησιμοποιεί Contract για αυστηρή τυποποίηση των δεδομένων εισόδου και εξόδου.

Κύρια σημεία

  • ActivityResultLauncher — το νέο API για λήψη αποτελέσματος από Activity αντί του ξεπερασμένου startActivityForResult
  • Contract — το αντικείμενο που καθορίζει τον τύπο δεδομένων εισόδου και εξόδου για ένα συγκεκριμένο σενάριο
  • Καταχώρηση γίνεται μέσω registerForActivityResult πριν από την κλήση launch
  • Callback — καλείται μετά την ολοκλήρωση του Activity-στόχου με το αποτέλεσμα
  • API διαθέσιμο για Activity, Fragment και Compose ξεκινώντας από Activity 1.2.0

Τι είναι το ActivityResultLauncher

ActivityResultLauncher είναι μια κλάση από το πακέτο androidx.activity.result που παρέχει έναν μηχανισμό ασφαλή ως προς τον τύπο για την εκκίνηση Activity και τη λήψη αποτελέσματος. Το Launcher δημιουργείται μέσω της μεθόδου registerForActivityResult, η οποία δέχεται δύο παραμέτρους: Contract (περιγράφει τους τύπους εισόδου και εξόδου) και ActivityResultCallback (χειριστής αποτελέσματος). Μετά την καταχώρηση, το launcher είναι έτοιμο για κλήση μέσω της μεθόδου launch.

Η βασική διαφορά από το παλιό API είναι ο διαχωρισμός καταχώρησης και εκκίνησης. Η καταχώρηση γίνεται στο στάδιο αρχικοποίησης (Activity.onCreate ή Fragment.onCreate), το callback συνδέεται με το launcher μία φορά και εγγυημένα ενεργοποιείται κατά την επιστροφή του αποτελέσματος. Αυτό εξαλείφει το πρόβλημα όπου το onActivityResult ενεργοποιούνταν σε απροσδόκητη σειρά ή σε ένα κατεστραμμένο Activity.

Το ActivityResultLauncher υποστηρίζει όλα τα σενάρια που προηγουμένως διαχειρίζονταν μέσω onActivityResult: εκκίνηση κάμερας, γκαλερί, αίτηση επαφών, αδειών και προσαρμοσμένων Activity. Επιπλέον, το API είναι επεκτάσιμο: ο προγραμματιστής μπορεί να δημιουργήσει δικά του Contract για συγκεκριμένα σενάρια ανταλλαγής δεδομένων μεταξύ Activity.

Γιατί το Activity Result API αντικατέστησε το startActivityForResult

startActivityForResult αποτελούσε μέρος του Android SDK από την έκδοση API Level 1 (2008) και παρέμεινε ο κύριος τρόπος λήψης αποτελέσματος από Activity για περισσότερα από 12 χρόνια. Ωστόσο, αυτή η μέθοδος είχε θεμελιώδη ελαττώματα που η Google εξάλειψε στο Activity Result API. Ας δούμε τα κύρια προβλήματα και πώς τα λύνει το νέο API.

Πρόβλημα 1: στενή σύνδεση με το Activity

Η μέθοδος startActivityForResult συνδέεται με το Activity και το Fragment μέσω requestCode — ενός αυθαίρετου ακέραιου αριθμού που μεταβιβάζεται στο onActivityResult. Ο προγραμματιστής ταίριαζε χειροκίνητα τον κωδικό με την εκκινούμενη λειτουργία, πράγμα που οδηγούσε σε σφάλματα κατά την επαναχρησιμοποίηση κώδικα και κληρονομικότητα. Το ActivityResultLauncher εξαλείφει εντελώς το requestCode: το callback συνδέεται με ένα συγκεκριμένο launcher στο στάδιο καταχώρησης και καλείται μόνο για αυτό.

Πρόβλημα 2: απώλεια αποτελέσματος κατά την περιστροφή οθόνης

Σε αλλαγές διαμόρφωσης (περιστροφή οθόνης, αλλαγή γλώσσας) το Activity αναδημιουργούνταν και το onActivityResult μπορεί να μην ενεργοποιούνταν — το callback χανόταν. Το Activity Result API αποθηκεύει και επαναφέρει αυτόματα την κατάσταση του launcher μέσω SavedStateRegistry, που εγγυάται τη λήψη του αποτελέσματος ακόμη και μετά την αναδημιουργία του Activity.

Πρόβλημα 3: έλλειψη ασφάλειας τύπων

Το παλιό API μετέφερε το αποτέλεσμα μέσω Intent με Bundle, όπου τα κλειδιά και οι τύποι δεδομένων δεν ελέγχονταν από τον μεταγλωττιστή. Το Activity Result API χρησιμοποιεί Contract — μια γενική διεπαφή που καθορίζει τον τύπο δεδομένων εισόδου (I) και τον τύπο αποτελέσματος (O). Σφάλματα ασυμφωνίας τύπων ανιχνεύονται στο στάδιο μεταγλώττισης, όχι κατά τον χρόνο εκτέλεσης.

ΧαρακτηριστικόstartActivityForResultActivityResultLauncher
RequestCodeΑπαιτεί χειροκίνητη διαχείρισηΑυτόματο, δεν απαιτείται
Ασφάλεια τύπωνΌχιGeneric Contract
Διατήρηση κατά περιστροφήΧάνεταιSavedStateRegistry
Ελάχιστο APIAPI Level 1Activity 1.2.0
Χρήση σε ComposeΔεν υποστηρίζεταιrememberLauncherForActivityResult

Κύρια συμβόλαια του Activity Result API

Contract είναι μια διεπαφή ActivityResultContract<I, O> που καθορίζει πώς να εκκινήσει το Activity και πώς να ερμηνεύσει το αποτέλεσμα. Η Google παρέχει ένα σύνολο ενσωματωμένων συμβολαίων για τυπικά σενάρια, καλύπτοντας τις περισσότερες ανάγκες του προγραμματιστή.

StartIntentSenderForResult

StartIntentSenderForResult είναι το βασικό συμβόλαιο για εκκίνηση IntentSender. Χρησιμοποιείται σε σενάρια συστήματος, για παράδειγμα κατά την αυθεντικοποίηση μέσω Google Sign-In ή κατά την πληρωμή μέσω Google Pay. Παράμετρος εισόδου — PendingIntent, έξοδος — ActivityResult με κωδικό και Intent.

RequestMultiplePermissions

RequestMultiplePermissions είναι το συμβόλαιο για ταυτόχρονη αίτηση πολλαπλών αδειών σε Android 6.0+. Παράμετρος εισόδου — πίνακας String με ονόματα αδειών, έξοδος — Map<String, Boolean> με το αποτέλεσμα κάθε αίτησης. Παλιότερα αυτό απαιτούσε χειροκίνητη ανάλυση στο onRequestPermissionsResult με αντιστοίχιση κωδικών αιτήσεων.

TakePicture και TakeVideo

TakePicture είναι το συμβόλαιο για λήψη φωτογραφίας μέσω κάμερας συστήματος. Είσοδος — Uri όπου αποθηκεύεται η φωτογραφία, έξοδος — Boolean (επιτυχία). TakeVideo λειτουργεί παρόμοια με βίντεο. Αυτά τα συμβόλαια αντικαθιστούν το ξεπερασμένο MediaStore.ACTION_IMAGE_CAPTURE με ασταθή συμπεριφορά σε διαφορετικές συσκευές.

GetContent και OpenDocument

GetContent είναι το συμβόλαιο για επιλογή περιεχομένου μέσω του επιλογέα συστήματος. Είσοδος — τύπος MIME (π.χ. image/*), έξοδος — Uri του επιλεγμένου αρχείου. OpenDocument διαφέρει με υποστήριξη πολλαπλής επιλογής και φιλτράρισμα ανά τύπο εγγράφου. Και τα δύο συμβόλαια λειτουργούν μέσω SAF (Storage Access Framework).

CreateDocument και OpenDocumentTree

CreateDocument είναι το συμβόλαιο για δημιουργία νέου εγγράφου μέσω διαλόγου συστήματος. Ο χρήστης επιλέγει όνομα και φάκελο, το σύστημα επιστρέφει Uri για εγγραφή. OpenDocumentTree παρέχει πρόσβαση σε ολόκληρο κατάλογο — ο χρήστης επιλέγει φάκελο και η εφαρμογή λαμβάνει tree-uri για ανάγνωση και εγγραφή όλων των αρχείων εντός αυτού.

Χρήση σε Activity και Fragment

Το βασικό μοτίβο χρήσης του ActivityResultLauncher στην κλασική Android αποτελείται από δύο βήματα: καταχώρηση μέσω registerForActivityResult στο στάδιο αρχικοποίησης και κλήση launch ως απόκριση σε ενέργεια χρήστη. Ας δούμε ένα τυπικό παράδειγμα επιλογής εικόνας από τη γκαλερί.

Καταχώρηση και εκκίνηση σε Activity

Καταχωρήστε το launcher στο onCreate του Activity — αυτό εγγυάται ότι το callback θα είναι έτοιμο πριν από οποιαδήποτε πιθανή κλήση. Μην καταχωρείτε ποτέ το launcher αμέσως πριν από την εκκίνηση — αυτό παραβιάζει το συμβόλαιο API και μπορεί να οδηγήσει σε απώλεια αποτελέσματος κατά την αναδημιουργία του 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/*")
    }
}

Χρήση σε Fragment

Σε Fragment η καταχώρηση γίνεται στο onCreate, onAttach ή αρχικοποίηση στο onCreateView. Το FragmentActivity μεταβιβάζει το launcher μέσω του γονικού Activity, οπότε το αποτέλεσμα επεξεργάζεται εντός του Fragment, όχι στο Activity. Αυτό βελτιώνει την ενθυλάκωση σε σύγκριση με το onActivityResult, όπου όλα τα αποτελέσματα από όλα τα Fragment συγκεντρώνονταν σε μία μέθοδο του Activity.

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

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

ActivityResultLauncher στο Jetpack Compose

Jetpack Compose παρέχει ειδική λειτουργικότητα composable για το Activity Result API — rememberLauncherForActivityResult. Σε αντίθεση με την κλασική προσέγγιση, στο Compose το launcher δημιουργείται ως αντικείμενο συνδεδεμένο με τον κύκλο ζωής του composable μέσω remember. Αυτό επιτρέπει τη χρήση του Activity Result API σε πλήρως δηλωτικό στυλ χωρίς άμεση πρόσβαση σε Activity ή Fragment.

rememberLauncherForActivityResult

rememberLauncherForActivityResult δέχεται Contract και callback, επιστρέφοντας ActivityResultLauncher. Το launcher διατηρείται κατά την ανασύνθεση και καθαρίζεται αυτόματα κατά την έξοδο από τη σύνθεση. Η κλήση launch γίνεται ως απόκριση σε συμβάν — για παράδειγμα, πάτημα κουμπιού ή αλλαγή κατάστασης.

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

    Button(onClick = { launcher.launch("image/*") }) {
        Text("Επιλογή φωτογραφίας")
    }
}

Διαχείριση αδειών στο Compose

Αίτηση αδειών στο Compose γίνεται επίσης μέσω rememberLauncherForActivityResult με συμβόλαιο RequestPermission ή RequestMultiplePermissions. Η Google συνιστά τη χρήση accompanist-permissions, αλλά κάτω από το καπό χρησιμοποιεί επίσης το Activity Result API. Για τον έλεγχο της κατάστασης των αδειών, είναι βολικό να αποθηκεύεται η κατάσταση σε remember ή ViewModel.

Συνηθισμένα λάθη και βέλτιστες πρακτικές

Activity Result API εξάλειψε πολλά προβλήματα της παλιάς προσέγγισης, αλλά η λανθασμένη χρήση του μπορεί να οδηγήσει σε νέα είδη σφαλμάτων. Ας δούμε τα πιο συνηθισμένα προβλήματα και τρόπους αποφυγής τους.

Λάθος: καταχώρηση εντός lambda ή coroutine

Η καταχώρηση του launcher πρέπει να γίνεται κατά την αρχικοποίηση του στοιχείου — στο onCreate του Activity ή στον αρχικοποιητή Fragment. Εάν καταχωρείτε το launcher εντός lambda, callback ή coroutine, κατά την αναδημιουργία του Activity η καταχώρηση μπορεί να εκτελεστεί ξανά και το παλιό launcher θα χάσει τη σύνδεση με το αποτέλεσμα.

Λάθος: καταχώρηση πολλαπλών launcher με το ίδιο κλειδί

Κάθε launcher λαμβάνει ένα μοναδικό κλειδί για αποθήκευση κατάστασης. Εάν καταχωρήσετε δύο launcher με το ίδιο Contract σε ένα στοιχείο, το SavedStateRegistry μπορεί να αντικαταστήσει την κατάσταση του ενός με του άλλου. Το Android Studio προειδοποιεί για αυτό μέσω του κανόνα lint UnnecessaryRegisterForActivityResult, αλλά είναι καλύτερο να ελέγχετε τη μοναδικότητα χειροκίνητα.

Βέλτιστη πρακτική: πάντα να χειρίζεστε το null αποτέλεσμα

Ο χρήστης μπορεί να ακυρώσει την ενέργεια — να πατήσει το πλήκτρο πίσω του συστήματος, να ελαχιστοποιήσει την εφαρμογή ή να μεταβεί σε άλλη εφαρμογή. Σε αυτή την περίπτωση, το callback θα λάβει null ή ActivityResult με RESULT_CANCELED. Πάντα ελέγχετε το αποτέλεσμα για null πριν από τη χρήση για να αποφύγετε το NullPointerException.

Βέλτιστη πρακτική: προσαρμοσμένα Contract για επαναχρησιμοποιήσιμη λογική

Εάν η εφαρμογή σας εκκινεί συχνά παρόμοια σενάρια — για παράδειγμα, επιλογή επαφής με επιστροφή ονόματος και τηλεφώνου — δημιουργήστε το δικό σας Contract. Αυτό βελτιώνει την αναγνωσιμότητα του κώδικα και επιτρέπει την κεντρική αλλαγή της λογικής εκκίνησης και επεξεργασίας αποτελέσματος.

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

Συχνές Ερωτήσεις

Μπορεί να χρησιμοποιηθεί το ActivityResultLauncher σε ViewModel;

Όχι — το ActivityResultLauncher απαιτεί περιβάλλον Activity ή Fragment για καταχώρηση. Χρησιμοποιήστε το ViewModel μόνο για αποθήκευση κατάστασης και δημιουργήστε το launcher σε Activity ή Fragment και μεταβιβάστε το αποτέλεσμα στο ViewModel.

Ποιο ελάχιστο SDK απαιτείται για το Activity Result API;

Activity Result API είναι διαθέσιμο ξεκινώντας από τη βιβλιοθήκη activity-ktx 1.2.0. Ελάχιστο SDK — API Level 14 (Android 4.0), αλλά τα περισσότερα συμβόλαια λειτουργούν μόνο σε API Level 19+.

Τι συμβαίνει αν το launch κληθεί δύο φορές πριν από τη λήψη αποτελέσματος;

Η επαναλαμβανόμενη κλήση του launch πριν από την ολοκλήρωση της πρώτης λειτουργίας θα αγνοηθεί. Το Activity Result API δεν υποστηρίζει παράλληλες εκκινήσεις — περιμένετε το callback από την πρώτη λειτουργία πριν από νέα κλήση.

Με τι να αντικαταστήσω το onActivityResult στον παλιό κώδικα;

Η μετεγκατάσταση γίνεται με αντικατάσταση της κλήσης startActivityForResult με registerForActivityResult με το αντίστοιχο Contract. Αφαιρέστε το onActivityResult και χειριστείτε το αποτέλεσμα στο callback του launcher. Η Google παρέχει οδηγό μετεγκατάστασης στην τεκμηρίωση Android Developers.

Λειτουργεί το ActivityResultLauncher με βιβλιοθήκες όπως ML Kit ή Barcode Scanner;

Ναι, πολλές βιβλιοθήκες υποστηρίζουν ενσωμάτωση μέσω ActivityResultContracts. Για παράδειγμα, το ML Kit Barcode Scanner χρησιμοποιεί StartIntentSenderForResult για εκκίνηση του σαρωτή. Ελέγξτε την τεκμηρίωση της συγκεκριμένης βιβλιοθήκης.

Σύνοψη

  • ActivityResultLauncher — σύγχρονο ασφαλές ως προς τον τύπο API αντί του ξεπερασμένου startActivityForResult
  • Contract καθορίζει τον τύπο δεδομένων εισόδου και εξόδου, εξαλείφοντας τη χειροκίνητη αντιστοίχιση requestCode
  • Καταχώρηση γίνεται στο στάδιο αρχικοποίησης, το αποτέλεσμα παραδίδεται εγγυημένα μέσω callback
  • Ενσωματωμένα συμβόλαια καλύπτουν κάμερα, γκαλερί, άδειες, έγγραφα και επαφές
  • Jetpack Compose χρησιμοποιεί rememberLauncherForActivityResult για εργασία με το API
  • Προσαρμοσμένα Contract επιτρέπουν επαναχρησιμοποίηση λογικής εκκίνησης μεταξύ στοιχείων
  • API διατηρεί κατάσταση σε αλλαγές διαμόρφωσης μέσω SavedStateRegistry

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης