ActivityResultLauncher Android Activity Result API का एक घटक है, जिसे androidx.activity लाइब्रेरी के Activity 1.2.0 संस्करण में पेश किया गया था। यह पुराने startActivityForResult और onActivityResult विधियों को बदलता है, जो Android SDK के निर्माण से ही इसका हिस्सा थीं। Android Developers (2024) के अनुसार, नया API Activity के साथ मजबूत युग्मन और टाइप सुरक्षा की कमी की समस्याओं को दूर करता है। ActivityResultLauncher पहले से पंजीकृत होता है और इनपुट और आउटपुट डेटा की सख्त टाइपिंग के लिए Contract का उपयोग करता है।
मुख्य बिंदु
ActivityResultLauncher androidx.activity.result पैकेज का एक वर्ग है जो Activity शुरू करने और परिणाम प्राप्त करने के लिए टाइप-सुरक्षित तंत्र प्रदान करता है। Launcher registerForActivityResult विधि के माध्यम से बनाया जाता है, जो दो पैरामीटर लेता है: Contract (इनपुट और आउटपुट प्रकारों का वर्णन करता है) और ActivityResultCallback (परिणाम हैंडलर)। पंजीकरण के बाद, launcher launch विधि के माध्यम से कॉल करने के लिए तैयार होता है।
पुराने API से मुख्य अंतर पंजीकरण और लॉन्च का पृथक्करण है। पंजीकरण आरंभीकरण चरण (Activity.onCreate या Fragment.onCreate) में किया जाता है, callback एक बार launcher से बंध जाता है और परिणाम लौटने पर इसे लागू होने की गारंटी होती है। यह उस समस्या को समाप्त करता है जहाँ onActivityResult अप्रत्याशित क्रम में या नष्ट की गई Activity पर लागू होता था।
ActivityResultLauncher सभी परिदृश्यों का समर्थन करता है जो पहले onActivityResult के माध्यम से संभाले जाते थे: कैमरा, गैलरी लॉन्च करना, संपर्क, अनुमतियाँ और कस्टम Activities का अनुरोध करना। इसके अलावा, API विस्तार योग्य है: डेवलपर Activities के बीच डेटा आदान-प्रदान के विशिष्ट परिदृश्यों के लिए कस्टम Contract बना सकते हैं।
startActivityForResult API Level 1 (2008) से Android SDK का हिस्सा रहा और 12 वर्षों से अधिक समय तक Activity से परिणाम प्राप्त करने का मुख्य तरीका बना रहा। हालाँकि, इस विधि में मूलभूत कमियाँ थीं जिन्हें Google ने Activity Result API में हल किया। आइए मुख्य समस्याओं और नए API द्वारा उनके समाधान पर नज़र डालें।
startActivityForResult विधि requestCode के माध्यम से Activity और Fragment से बंधी होती है — एक मनमाना पूर्णांक जो onActivityResult को पास किया जाता है। डेवलपर मैन्युअल रूप से कोड को शुरू किए गए ऑपरेशन से मिलाता था, जिससे कोड पुन: उपयोग और इनहेरिटेंस में त्रुटियाँ होती थीं। ActivityResultLauncher requestCode को पूरी तरह से समाप्त कर देता है: callback पंजीकरण के समय एक विशिष्ट launcher से बंध जाता है और केवल उसके लिए लागू होता है।
कॉन्फ़िगरेशन परिवर्तनों (स्क्रीन घूमना, भाषा बदलना) के दौरान, Activity पुनः बनाई जाती थी और onActivityResult लागू नहीं हो सकता था — callback खो जाता था। Activity Result API SavedStateRegistry के माध्यम से स्वचालित रूप से launcher स्थिति को सहेजता और पुनर्स्थापित करता है, जिससे Activity पुनर्निर्माण के बाद भी परिणाम प्राप्त करने की गारंटी मिलती है।
पुराना API परिणाम Bundle के साथ Intent के माध्यम से पास करता था, जहाँ कुंजियों और डेटा प्रकारों की जाँच कंपाइलर द्वारा नहीं की जाती थी। Activity Result API Contract का उपयोग करता है — एक जेनेरिक इंटरफ़ेस जो इनपुट डेटा प्रकार (I) और परिणाम प्रकार (O) को परिभाषित करता है। प्रकार बेमेल त्रुटियाँ रनटाइम के बजाय कंपाइल समय पर पकड़ी जाती हैं।
| विशेषता | startActivityForResult | ActivityResultLauncher |
|---|---|---|
| RequestCode | मैन्युअल प्रबंधन आवश्यक | स्वचालित, आवश्यक नहीं |
| टाइप सुरक्षा | नहीं | जेनेरिक Contract |
| घूमने पर सहेजना | खो जाता है | SavedStateRegistry |
| न्यूनतम API | API Level 1 | Activity 1.2.0 |
| Compose में उपयोग | समर्थित नहीं | rememberLauncherForActivityResult |
Contract ActivityResultContract<I, O> इंटरफ़ेस है, जो परिभाषित करता है कि Activity कैसे शुरू करें और परिणाम की व्याख्या कैसे करें। Google विशिष्ट परिदृश्यों के लिए अंतर्निहित कॉन्ट्रैक्ट का एक सेट प्रदान करता है जो अधिकांश डेवलपर आवश्यकताओं को कवर करता है।
StartIntentSenderForResult — IntentSender शुरू करने के लिए एक मूल कॉन्ट्रैक्ट। सिस्टम परिदृश्यों में उपयोग किया जाता है, उदाहरण के लिए Google Sign-In के माध्यम से प्राधिकरण या Google Pay के माध्यम से भुगतान करते समय। इनपुट पैरामीटर PendingIntent है, आउटपुट कोड और Intent के साथ ActivityResult है।
RequestMultiplePermissions — Android 6.0+ पर एक साथ कई अनुमतियों का अनुरोध करने के लिए कॉन्ट्रैक्ट। इनपुट पैरामीटर अनुमति नामों वाली String सरणी है, आउटपुट प्रत्येक अनुरोध के परिणाम के साथ Map<String, Boolean> है। पहले इसके लिए onRequestPermissionsResult में अनुरोध कोड मिलान के साथ मैन्युअल पार्सिंग की आवश्यकता होती थी।
TakePicture — सिस्टम कैमरे के माध्यम से फोटो लेने के लिए कॉन्ट्रैक्ट। इनपुट Uri है जहाँ छवि सहेजनी है, आउटपुट Boolean (सफलता) है। TakeVideo वीडियो के साथ समान रूप से काम करता है। ये कॉन्ट्रैक्ट विभिन्न उपकरणों पर अस्थिर व्यवहार वाले पुराने MediaStore.ACTION_IMAGE_CAPTURE को बदलते हैं।
GetContent — सिस्टम पिकर के माध्यम से सामग्री चुनने के लिए कॉन्ट्रैक्ट। इनपुट MIME प्रकार है (जैसे image/*), आउटपुट चयनित फ़ाइल का Uri है। OpenDocument एकाधिक चयन और दस्तावेज़ प्रकारों द्वारा फ़िल्टरिंग का समर्थन करने में भिन्न है। दोनों कॉन्ट्रैक्ट SAF (Storage Access Framework) के माध्यम से काम करते हैं।
CreateDocument — सिस्टम डायलॉग के माध्यम से नया दस्तावेज़ बनाने के लिए कॉन्ट्रैक्ट। उपयोगकर्ता नाम और फ़ोल्डर चुनता है, सिस्टम लिखने के लिए Uri लौटाता है। OpenDocumentTree पूरी निर्देशिका तक पहुँच प्रदान करता है — उपयोगकर्ता एक फ़ोल्डर चुनता है, और ऐप अंदर的所有 फ़ाइलों को पढ़ने और लिखने के लिए tree-uri प्राप्त करता है।
मूल पैटर्न क्लासिक Android में ActivityResultLauncher का उपयोग करने के लिए दो चरणों का है: आरंभीकरण पर registerForActivityResult के माध्यम से पंजीकरण और उपयोगकर्ता क्रिया के जवाब में launch कॉल करना। आइए गैलरी से छवि चुनने के एक विशिष्ट उदाहरण पर नज़र डालें।
Launcher को Activity के onCreate में पंजीकृत करें — यह सुनिश्चित करता है कि किसी भी संभावित कॉल से पहले callback तैयार हो। लॉन्च करने से ठीक पहले launcher को कभी पंजीकृत न करें — यह API कॉन्ट्रैक्ट का उल्लंघन करता है और 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/*")
}
}
Fragment में, पंजीकरण onCreate, onAttach या onCreateView में आरंभीकरण में किया जाता है। FragmentActivity पैरेंट Activity के माध्यम से launcher पास करता है, इसलिए परिणाम Activity के बजाय Fragment के अंदर संसाधित होता है। यह onActivityResult की तुलना में एनकैप्सुलेशन में सुधार करता है, जहाँ सभी Fragments के सभी परिणाम एक Activity विधि में एकत्रित होते थे।
class ProfileFragment : Fragment() {
private val cameraLauncher =
registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
if (success) { updateProfilePhoto() }
}
fun takePhoto(photoUri: Uri) {
cameraLauncher.launch(photoUri)
}
}
Jetpack Compose Activity Result API के लिए एक विशेष composable फ़ंक्शन प्रदान करता है — rememberLauncherForActivityResult। क्लासिक दृष्टिकोण के विपरीत, Compose में launcher remember के माध्यम से composable जीवनचक्र से बंधी एक वस्तु के रूप में बनाया जाता है। यह Activity या Fragment तक सीधी पहुँच के बिना पूरी तरह से घोषणात्मक शैली में Activity Result API का उपयोग करने की अनुमति देता है।
rememberLauncherForActivityResult Contract और callback लेता है, और ActivityResultLauncher लौटाता है। पुनर्संयोजन के दौरान launcher संरक्षित रहता है और संरचना छोड़ने पर स्वचालित रूप से साफ़ हो जाता है। launch कॉल किसी घटना के जवाब में होती है — उदाहरण के लिए, बटन क्लिक या स्थिति परिवर्तन।
@Composable
fun PhotoPicker() {
val context = LocalContext.current
val launcher = rememberLauncherForActivityResult(
ActivityResultContracts.GetContent()
) { uri -> handleImage(uri) }
Button(onClick = { launcher.launch("image/*") }) {
Text("फ़ोटो चुनें")
}
}
Compose में अनुमति अनुरोध भी RequestPermission या RequestMultiplePermissions कॉन्ट्रैक्ट के साथ rememberLauncherForActivityResult के माध्यम से किए जाते हैं। Google accompanist-permissions का उपयोग करने की अनुशंसा करता है, लेकिन यह आंतरिक रूप से भी Activity Result API का उपयोग करता है। अनुमति स्थिति को ट्रैक करने के लिए, स्थिति को remember या ViewModel में संग्रहीत करना सुविधाजनक है।
Activity Result API ने पुराने दृष्टिकोण की कई समस्याओं को समाप्त कर दिया, लेकिन अनुचित उपयोग नई प्रकार की त्रुटियों का कारण बन सकता है। आइए सबसे सामान्य समस्याओं और उनसे बचने के तरीकों पर नज़र डालें।
Launcher का पंजीकरण घटक आरंभीकरण के दौरान किया जाना चाहिए — Activity onCreate या Fragment आरंभकर्ता में। यदि आप lambda, callback या coroutine के अंदर launcher पंजीकृत करते हैं, तो Activity पुनर्निर्माण पर पंजीकरण फिर से किया जा सकता है और पुराना launcher परिणाम से संपर्क खो देगा।
प्रत्येक launcher को स्थिति सहेजने के लिए एक अद्वितीय कुंजी मिलती है। यदि आप एक घटक में एक ही Contract के साथ दो launchers पंजीकृत करते हैं, तो SavedStateRegistry एक की स्थिति को दूसरे से अधिलेखित कर सकता है। Android Studio lint नियम UnnecessaryRegisterForActivityResult के माध्यम से इसके बारे में चेतावनी देता है, लेकिन विशिष्टता को मैन्युअल रूप से नियंत्रित करना बेहतर है।
उपयोगकर्ता क्रिया को रद्द कर सकता है — सिस्टम बैक बटन दबाएँ, ऐप को छोटा करें, या किसी अन्य ऐप पर स्विच करें। इस मामले में, callback null या RESULT_CANCELED के साथ ActivityResult प्राप्त करेगा। NullPointerException से बचने के लिए उपयोग करने से पहले हमेशा null के लिए परिणाम की जाँच करें।
यदि आपका ऐप बार-बार समान परिदृश्य शुरू करता है — उदाहरण के लिए, संपर्क चुनना और नाम और फ़ोन लौटाना — तो कस्टम Contract बनाएँ। यह कोड पठनीयता में सुधार करता है और लॉन्च और परिणाम प्रबंधन तर्क में केंद्रीय परिवर्तन की अनुमति देता है।
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 को पंजीकरण के लिए Activity या Fragment संदर्भ की आवश्यकता होती है। ViewModel का उपयोग केवल स्थिति संग्रहीत करने के लिए करें, और launcher को Activity या Fragment में बनाएँ और परिणाम ViewModel को पास करें।
Activity Result API लाइब्रेरी activity-ktx 1.2.0 से उपलब्ध है। न्यूनतम SDK API Level 14 (Android 4.0) है, लेकिन अधिकांश कॉन्ट्रैक्ट केवल API Level 19+ पर काम करते हैं।
पहले ऑपरेशन के पूरा होने से पहले launch का दोहरा कॉल अनदेखा कर दिया जाएगा। Activity Result API समानांतर लॉन्च का समर्थन नहीं करता — नया कॉल करने से पहले पहले ऑपरेशन से callback की प्रतीक्षा करें।
माइग्रेशन उपयुक्त Contract के साथ startActivityForResult कॉल को registerForActivityResult से बदलकर किया जाता है। onActivityResult हटाएँ और launcher callback में परिणाम संभालें। Google Android Developers दस्तावेज़ीकरण में माइग्रेशन गाइड प्रदान करता है।
हाँ, कई लाइब्रेरी ActivityResultContracts के माध्यम से एकीकरण का समर्थन करती हैं। उदाहरण के लिए, ML Kit Barcode Scanner स्कैनर शुरू करने के लिए StartIntentSenderForResult का उपयोग करती है। विशिष्ट लाइब्रेरी के दस्तावेज़ीकरण की जाँच करें।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें