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 کے ذریعے سنبھالے جاتے تھے: کیمرہ شروع کرنا، گیلری، رابطوں کی درخواست، اجازتیں اور حسب ضرورت Activity۔ مزید برآں، API قابل توسیع ہے: ڈویلپر Activity کے درمیان ڈیٹا کے تبادلے کے مخصوص منظرناموں کے لیے حسب ضرورت 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 کے مقابلے میں انکیپسولیشن کو بہتر بناتا ہے، جہاں تمام Fragment کے تمام نتائج ایک 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 کے ابتداکار میں۔ اگر آپ launcher کو lambda، callback یا coroutine کے اندر رجسٹر کرتے ہیں، تو 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 ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں