ActivityResultLauncher — Android Activity Result API komponenti bo'lib, androidx.activity kutubxonasining Activity 1.2.0 versiyasida taqdim etilgan. U Android SDK yaratilgan paytdan boshlab uning bir qismi bo'lgan eskirgan startActivityForResult va onActivityResult metodlarini almashtiradi. Android Developers (2024) ma'lumotlariga ko'ra, yangi API Activity bilan qattiq bog'liqlik va tip xavfsizligining yo'qligi muammolarini bartaraf etadi. ActivityResultLauncher oldindan ro'yxatdan o'tkaziladi va kirish va chiqish ma'lumotlarining qat'iy tiplanishi uchun Contract-dan foydalanadi.
Asosiy ma'lumotlar
ActivityResultLauncher — androidx.activity.result paketidagi sinf bo'lib, Activity ni ishga tushirish va natija olish uchun tip xavfsiz mexanizmni taqdim etadi. Launcher registerForActivityResult metodi orqali yaratiladi, u ikkita parametrni qabul qiladi: Contract (kirish va chiqish turlarini tavsiflaydi) va ActivityResultCallback (natija ishlovchisi). Ro'yxatdan o'tkazilgandan so'ng, launcher launch metodi orqali chaqirishga tayyor.
Eski API dan asosiy farq — ro'yxatdan o'tkazish va ishga tushirishning ajratilishidir. Ro'yxatdan o'tkazish ishga tushirish bosqichida (Activity.onCreate yoki Fragment.onCreate) amalga oshiriladi, callback launcher bilan bir marta bog'lanadi va natija qaytganda kafolatlangan holda ishga tushadi. Bu onActivityResult kutilmagan tartibda yoki yo'q qilingan Activity da ishga tushishi muammosini bartaraf etadi.
ActivityResultLauncher ilgari onActivityResult orqali qayta ishlangan barcha stsenariylarni qo'llab-quvvatlaydi: kamera, galereya, kontaktlar so'rovi, ruxsatnomalar va maxsus Activity larni ishga tushirish. Bundan tashqari, API kengaytirilishi mumkin: dasturchi Activity lar o'rtasida ma'lumot almashishning o'ziga xos stsenariylari uchun o'z Contract larini yaratishi mumkin.
startActivityForResult Android SDK ning API Level 1 (2008) versiyasidan boshlab uning bir qismi bo'lgan va 12 yildan ortiq vaqt davomida Activity dan natija olishning asosiy usuli bo'lib qoldi. Biroq, bu metod Google Activity Result API da bartaraf etgan fundamental kamchiliklarga ega edi. Keling, asosiy muammolar va yangi API ularni qanday hal qilishini ko'rib chiqaylik.
startActivityForResult metodi Activity va Fragment bilan requestCode orqali bog'langan — onActivityResult ga uzatiladigan ixtiyoriy butun son. Dasturchi kodni ishga tushirilgan operatsiya bilan qo'lda moslashtirardi, bu kodni qayta ishlatish va meros olishda xatolarga olib keldi. ActivityResultLauncher requestCode ni butunlay yo'q qiladi: callback ro'yxatdan o'tkazish bosqichida muayyan launcher ga bog'lanadi va faqat u uchun chaqiriladi.
Konfiguratsiya o'zgarishlari (ekran aylantirish, tilni o'zgartirish) vaqtida Activity qayta yaratildi va onActivityResult ishga tushmasligi mumkin edi — callback yo'qoldi. Activity Result API SavedStateRegistry orqali launcher holatini avtomatik saqlaydi va tiklaydi, bu Activity qayta yaratilgandan keyin ham natija olishni kafolatlaydi.
Eski API natijani Bundle bilan Intent orqali uzatardi, bunda kalitlar va ma'lumotlar turlari kompilyator tomonidan tekshirilmagan. Activity Result API Contract — kirish ma'lumotlarining turini (I) va natija turini (O) belgilaydigan generic interfeysdan foydalanadi. Tur mos kelmasligi xatolari runtime da emas, kompilyatsiya bosqichida aniqlanadi.
| Xarakteristika | startActivityForResult | ActivityResultLauncher |
|---|---|---|
| RequestCode | Qo'lda boshqarish talab qilinadi | Avtomatik, talab qilinmaydi |
| Tip xavfsizligi | Yo'q | Generic Contract |
| Aylantirishda saqlash | Yo'qoladi | SavedStateRegistry |
| Minimal API | API Level 1 | Activity 1.2.0 |
| Compose da foydalanish | Qo'llab-quvvatlanmaydi | rememberLauncherForActivityResult |
Contract — ActivityResultContract<I, O> interfeysi bo'lib, Activity ni qanday ishga tushirish va natijani qanday talqin qilishni belgilaydi. Google dasturchining aksariyat ehtiyojlarini qoplaydigan odatiy stsenariylar uchun o'rnatilgan kontraktlar to'plamini taqdim etadi.
StartIntentSenderForResult — IntentSender ni ishga tushirish uchun asosiy kontrakt. Tizim stsenariylarida, masalan Google Sign-In orqali avtorizatsiya yoki Google Pay orqali to'lovda foydalaniladi. Kirish parametri — PendingIntent, chiqish — kod va Intent bilan ActivityResult.
RequestMultiplePermissions — Android 6.0+ da bir vaqtning o'zida bir nechta ruxsatnoma so'rash uchun kontrakt. Kirish parametri — ruxsatnomalar nomlari bilan String massivi, chiqish — har bir so'rov natijasi bilan Map<String, Boolean>. Ilgari bu so'rov kodlarini moslashtirish bilan onRequestPermissionsResult da qo'lda tahlil qilishni talab qilardi.
TakePicture — tizim kamerasi orqali suratga olish uchun kontrakt. Kirish — surat saqlanadigan Uri, chiqish — Boolean (muvaffaqiyat). TakeVideo xuddi shunday video bilan ishlaydi. Ushbu kontraktlar turli qurilmalarda beqaror xatti-harakatga ega bo'lgan eskirgan MediaStore.ACTION_IMAGE_CAPTURE o'rnini egallaydi.
GetContent — tizim picker orqali kontent tanlash uchun kontrakt. Kirish — MIME turi (masalan image/*), chiqish — tanlangan faylning Uri si. OpenDocument bir nechta tanlashni qo'llab-quvvatlash va hujjat turlari bo'yicha filtrlash bilan farqlanadi. Ikkala kontrakt SAF (Storage Access Framework) orqali ishlaydi.
CreateDocument — tizim dialog oynasi orqali yangi hujjat yaratish uchun kontrakt. Foydalanuvchi nom va papkani tanlaydi, tizim yozish uchun Uri qaytaradi. OpenDocumentTree butun katalogga kirishni beradi — foydalanuvchi papkani tanlaydi va ilova ichidagi barcha fayllarni o'qish va yozish uchun tree-uri oladi.
Klassik Android da ActivityResultLauncher dan foydalanishning asosiy namunasi ikki bosqichdan iborat: ishga tushirish bosqichida registerForActivityResult orqali ro'yxatdan o'tkazish va foydalanuvchi harakatiga javoban launch chaqiruvi. Keling, galereyadan rasm tanlashning odatiy misolini ko'rib chiqaylik.
Launcher ni Activity ning onCreate da ro'yxatdan o'tkazing — bu callback har qanday mumkin bo'lgan chaqiruvdan oldin tayyor bo'lishini kafolatlaydi. Hech qachon launcher ni to'g'ridan-to'g'ri ishga tushirishdan oldin ro'yxatdan o'tkazmang — bu API kontraktini buzadi va Activity qayta yaratilganda natijani yo'qotishga olib kelishi mumkin.
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 da ro'yxatdan o'tkazish onCreate, onAttach yoki onCreateView dagi ishga tushirishda amalga oshiriladi. FragmentActivity launcher ni ota Activity orqali uzatadi, shuning uchun natija Activity da emas, Fragment ichida qayta ishlanadi. Bu onActivityResult bilan solishtirganda inkapsulyatsiyani yaxshilaydi, bunda barcha Fragment lardan barcha natijalar Activity ning bitta metodida to'plangan.
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 uchun maxsus composable funksionallikni taqdim etadi — rememberLauncherForActivityResult. Klassik yondashuvdan farqli o'laroq, Compose da launcher remember orqali composable hayot aylanishiga bog'langan ob'ekt sifatida yaratiladi. Bu Activity yoki Fragment ga to'g'ridan-to'g'ri kirishsiz Activity Result API dan to'liq deklarativ uslubda foydalanish imkonini beradi.
rememberLauncherForActivityResult Contract va callback ni qabul qiladi, ActivityResultLauncher qaytaradi. Launcher rekompozitsiya vaqtida saqlanadi va kompozitsiyadan chiqishda avtomatik tozalanadi. launch chaqiruvi hodisaga javoban sodir bo'ladi — masalan, tugmani bosish yoki holatni o'zgartirish.
@Composable
fun PhotoPicker() {
val context = LocalContext.current
val launcher = rememberLauncherForActivityResult(
ActivityResultContracts.GetContent()
) { uri -> handleImage(uri) }
Button(onClick = { launcher.launch("image/*") }) {
Text("Rasmni tanlang")
}
}
Compose da ruxsatnomalarni so'rash ham RequestPermission yoki RequestMultiplePermissions kontrakti bilan rememberLauncherForActivityResult orqali amalga oshiriladi. Google accompanist-permissions dan foydalanishni tavsiya qiladi, ammo u ham ichki ravishda Activity Result API dan foydalanadi. Ruxsatnoma holatini nazorat qilish uchun statusni remember yoki ViewModel da saqlash qulay.
Activity Result API eski yondashuvning ko'plab muammolarini bartaraf etdi, ammo uni noto'g'ri ishlatish yangi turdagi xatolarga olib kelishi mumkin. Keling, eng keng tarqalgan muammolar va ulardan qochish usullarini ko'rib chiqaylik.
Launcher ni ro'yxatdan o'tkazish komponentni ishga tushirish vaqtida — Activity ning onCreate ida yoki Fragment ning ishga tushiruvchisida amalga oshirilishi kerak. Agar launcher ni lambda, callback yoki korutin ichida ro'yxatdan o'tkazsangiz, Activity qayta yaratilganda ro'yxatdan o'tkazish takrorlanishi mumkin va eski launcher natija bilan aloqani yo'qotadi.
Har bir launcher holatni saqlash uchun noyob kalit oladi. Agar bitta komponentda bir xil Contract bilan ikkita launcher ro'yxatdan o'tkazsangiz, SavedStateRegistry birining holatini ikkinchisining ustiga yozishi mumkin. Android Studio bu haqda UnnecessaryRegisterForActivityResult lint qoidasi orqali ogohlantiradi, ammo noyoblikni qo'lda nazorat qilish yaxshiroqdir.
Foydalanuvchi harakatni bekor qilishi mumkin — tizimning orqaga tugmasini bosish, ilovani minimallashtirish yoki boshqa ilovaga o'tish. Bunday holda callback null yoki RESULT_CANCELED bilan ActivityResult oladi. NullPointerException dan qochish uchun ishlatishdan oldin natijani har doim null ga tekshiring.
Agar ilovangiz tez-tez bir xil turdagi stsenariylarni ishga tushirsa — masalan, ism va telefon qaytaradigan kontakt tanlash — o'zingizning Contract ingizni yarating. Bu kod o'qilishini yaxshilaydi va ishga tushirish va natijani qayta ishlash mantiqini markazlashtirilgan holda o'zgartirish imkonini beradi.
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) }
}
Tez-tez beriladigan savollar
Yo'q — ActivityResultLauncher ro'yxatdan o'tkazish uchun Activity yoki Fragment kontekstini talab qiladi. ViewModel dan faqat holatni saqlash uchun foydalaning, launcher ni esa Activity yoki Fragment da yarating va natijani ViewModel ga uzating.
Activity Result API activity-ktx 1.2.0 kutubxonasidan boshlab mavjud. Minimal SDK — API Level 14 (Android 4.0), ammo aksariyat kontraktlar faqat API Level 19+ da ishlaydi.
Takroriy launch chaqiruvi birinchi operatsiya tugaguniga qadar e'tiborga olinmaydi. Activity Result API parallel ishga tushirishlarni qo'llab-quvvatlamaydi — yangi chaqiruvdan oldin birinchi operatsiyadan callback ni kuting.
Migratsiya startActivityForResult chaqiruvini tegishli Contract bilan registerForActivityResult ga almashtirish orqali amalga oshiriladi. onActivityResult ni olib tashlang va natijani launcher callback ida qayta ishlang. Google Android Developers hujjatlarida migratsiya bo'yicha qo'llanma taqdim etadi.
Ha, ko'plab kutubxonalar ActivityResultContracts orqali integratsiyani qo'llab-quvvatlaydi. Masalan, ML Kit Barcode Scanner skanerni ishga tushirish uchun StartIntentSenderForResult dan foydalanadi. Muayyan kutubxonaning hujjatlarini tekshiring.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.