ActivityResultLauncher, androidx.activity kütüphanesinin Activity 1.2.0 sürümünde tanıtılan Android Activity Result API’nin bir bileşenidir. Android SDK’nın oluşturulmasından bu yana parçası olan kullanımdan kaldırılmış startActivityForResult ve onActivityResult yöntemlerinin yerini alır. Android Developers (2024)’e göre, yeni API, Activity ile sıkı bağlantı ve tür güvenliği eksikliği sorunlarını ortadan kaldırır. ActivityResultLauncher önceden kaydedilir ve giriş ve çıkış verilerinin sıkı tür tanımlaması için Contract kullanır.
Ana Noktalar
ActivityResultLauncher, androidx.activity.result paketinden bir sınıftır ve bir Activity başlatmak ve sonuç almak için tür güvenli bir mekanizma sağlar. Launcher, iki parametre alan registerForActivityResult yöntemiyle oluşturulur: Contract (giriş ve çıkış türlerini tanımlar) ve ActivityResultCallback (sonuç işleyicisi). Kayıttan sonra launcher, launch yöntemiyle çağrılmaya hazırdır.
Eski API’den temel fark, kayıt ve başlatmanın ayrılmasıdır. Kayıt, başlatma aşamasında (Activity.onCreate veya Fragment.onCreate) gerçekleştirilir, callback launcher’a bir kez bağlanır ve sonuç döndüğünde çalışması garanti edilir. Bu, onActivityResult’un beklenmedik bir sırada veya yok edilmiş bir Activity’de çalışması sorununu ortadan kaldırır.
ActivityResultLauncher, daha önce onActivityResult aracılığıyla işlenen tüm senaryoları destekler: kamerayı başlatma, galeri, kişileri isteme, izinler ve özel Activity’ler. Ayrıca, API genişletilebilir: geliştiriciler, Activity’ler arasındaki belirli veri alışveriş senaryoları için özel Contract’lar oluşturabilir.
startActivityForResult, API Level 1’den (2008) beri Android SDK’nın bir parçasıydı ve 12 yıldan fazla bir süre boyunca bir Activity’den sonuç almanın ana yöntemi olarak kaldı. Ancak, bu yöntemin Google’ın Activity Result API’de çözdüğü temel eksiklikleri vardı. Ana sorunlara ve yeni API’nin bunları nasıl çözdüğüne bakalım.
startActivityForResult yöntemi, requestCode (onActivityResult’a iletilen rastgele bir tam sayı) aracılığıyla Activity ve Fragment’e bağlıdır. Geliştirici, kodu başlatılan işlemle manuel olarak eşleştiriyordu ve bu da kod yeniden kullanımı ve kalıtımda hatalara yol açıyordu. ActivityResultLauncher requestCode’u tamamen ortadan kaldırır: callback, kayıt sırasında belirli bir launcher’a bağlanır ve yalnızca onun için çağrılır.
Yapılandırma değişiklikleri sırasında (ekran döndürme, dil değişimi), Activity yeniden oluşturuluyordu ve onActivityResult çalışmayabilirdi — callback kayboluyordu. Activity Result API, SavedStateRegistry aracılığıyla launcher durumunu otomatik olarak kaydeder ve geri yükler, böylece Activity yeniden oluşturulduktan sonra bile sonucun alınmasını garanti eder.
Eski API, anahtarların ve veri türlerinin derleyici tarafından kontrol edilmediği bir Bundle ile Intent aracılığıyla sonucu iletiyordu. Activity Result API, Contract — giriş veri türünü (I) ve sonuç türünü (O) tanımlayan genel bir arayüz — kullanır. Tür uyuşmazlığı hataları, çalışma zamanında değil, derleme zamanında yakalanır.
| Özellik | startActivityForResult | ActivityResultLauncher |
|---|---|---|
| RequestCode | Manuel yönetim gerekli | Otomatik, gerekli değil |
| Tür güvenliği | Hayır | Genel Contract |
| Döndürmede kaydetme | Kaybolur | SavedStateRegistry |
| Minimum API | API Level 1 | Activity 1.2.0 |
| Compose’da kullanım | Desteklenmez | rememberLauncherForActivityResult |
Contract, bir Activity’nin nasıl başlatılacağını ve sonucun nasıl yorumlanacağını tanımlayan ActivityResultContract<I, O> arayüzüdür. Google, çoğu geliştirici ihtiyacını karşılayan tipik senaryolar için bir dizi yerleşik kontrat sağlar.
StartIntentSenderForResult — IntentSender başlatmak için temel bir kontrat. Sistem senaryolarında kullanılır, örneğin Google Sign-In ile yetkilendirme veya Google Pay ile ödeme yaparken. Giriş parametresi PendingIntent’tir, çıkış ise kod ve Intent ile ActivityResult’tur.
RequestMultiplePermissions — Android 6.0+’da aynı anda birden fazla izin istemek için bir kontrat. Giriş parametresi izin adlarından oluşan bir String dizisidir, çıkış ise her isteğin sonucunu içeren Map<String, Boolean>’dur. Daha önce bu, onRequestPermissionsResult içinde istek kodlarını eşleştirerek manuel ayrıştırma gerektiriyordu.
TakePicture — sistem kamerasıyla fotoğraf çekmek için bir kontrat. Giriş, görüntünün kaydedileceği Uri’dir, çıkış ise Boolean (başarı)’dır. TakeVideo video ile benzer şekilde çalışır. Bu kontratlar, farklı cihazlarda dengesiz davranış gösteren kullanımdan kaldırılmış MediaStore.ACTION_IMAGE_CAPTURE’un yerini alır.
GetContent — sistem seçici aracılığıyla içerik seçmek için bir kontrat. Giriş bir MIME türüdür (örn. image/*), çıkış seçilen dosyanın Uri’sidir. OpenDocument, çoklu seçim ve belge türlerine göre filtrelemeyi desteklemesiyle ayrılır. Her iki kontrat da SAF (Storage Access Framework) aracılığıyla çalışır.
CreateDocument — sistem diyaloğu aracılığıyla yeni bir belge oluşturmak için bir kontrat. Kullanıcı bir ad ve klasör seçer, sistem yazma için bir Uri döndürür. OpenDocumentTree tam bir dizine erişim sağlar — kullanıcı bir klasör seçer ve uygulama içindeki tüm dosyaları okumak ve yazmak için bir tree-uri alır.
Klasik Android’de ActivityResultLauncher kullanmanın temel deseni iki adımdan oluşur: başlatma sırasında registerForActivityResult aracılığıyla kayıt ve kullanıcı eylemine yanıt olarak launch çağrısı. Galeriden bir görüntü seçmenin tipik bir örneğine bakalım.
Launcher’ı Activity’nin onCreate’inde kaydedin — bu, olası herhangi bir çağrıdan önce callback’in hazır olmasını sağlar. Bir launcher’ı asla başlatmadan hemen önce kaydetmeyin — bu API kontratını ihlal eder ve Activity yeniden oluşturulduğunda sonuç kaybına yol açabilir.
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/*")
}
}
Bir Fragment’te kayıt, onCreate, onAttach veya onCreateView’de başlatma sırasında yapılır. FragmentActivity, launcher’ı üst Activity aracılığıyla iletir, böylece sonuç Activity’de değil, Fragment içinde işlenir. Bu, tüm Fragment’lerden gelen tüm sonuçların tek bir Activity yönteminde toplandığı onActivityResult’a kıyasla kapsüllemeyi iyileştirir.
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 için özel bir composable işlevi sağlar — rememberLauncherForActivityResult. Klasik yaklaşımın aksine, Compose’da launcher, remember aracılığıyla composable yaşam döngüsüne bağlı bir nesne olarak oluşturulur. Bu, Activity veya Fragment’e doğrudan erişim olmadan Activity Result API’nin tamamen bildirimsel bir stilde kullanılmasına olanak tanır.
rememberLauncherForActivityResult bir Contract ve callback alır ve bir ActivityResultLauncher döndürür. Launcher, yeniden oluşturma sırasında korunur ve kompozisyondan çıkıldığında otomatik olarak temizlenir. launch çağrısı bir olaya yanıt olarak gerçekleşir — örneğin, bir düğme tıklaması veya durum değişikliği.
@Composable
fun PhotoPicker() {
val context = LocalContext.current
val launcher = rememberLauncherForActivityResult(
ActivityResultContracts.GetContent()
) { uri -> handleImage(uri) }
Button(onClick = { launcher.launch("image/*") }) {
Text("Fotoğraf seç")
}
}
Compose’da izin talepleri de RequestPermission veya RequestMultiplePermissions kontratı ile rememberLauncherForActivityResult aracılığıyla yapılır. Google, accompanist-permissions kullanımını önerir, ancak içte o da Activity Result API’yi kullanır. İzin durumunu izlemek için durumu remember veya ViewModel’de saklamak uygundur.
Activity Result API, eski yaklaşımın birçok sorununu ortadan kaldırdı, ancak yanlış kullanım yeni tür hatalara yol açabilir. En yaygın sorunlara ve bunlardan nasıl kaçınılacağına bakalım.
Launcher’ın kaydı, bileşen başlatma sırasında — Activity’nin onCreate’inde veya Fragment başlatıcısında yapılmalıdır. Launcher’ı bir lambda, callback veya coroutine içinde kaydederseniz, Activity yeniden oluşturulduğunda kayıt tekrar yapılabilir ve eski launcher sonuçla bağlantısını kaybeder.
Her launcher durum kaydetme için benzersiz bir anahtar alır. Bir bileşende aynı Contract’a sahip iki launcher kaydederseniz, SavedStateRegistry birinin durumunu diğeriyle üzerine yazabilir. Android Studio, lint kuralı UnnecessaryRegisterForActivityResult aracılığıyla bu konuda uyarır, ancak benzersizliği manuel olarak kontrol etmek daha iyidir.
Kullanıcı eylemi iptal edebilir — sistem geri düğmesine basabilir, uygulamayı küçültebilir veya başka bir uygulamaya geçebilir. Bu durumda, callback null veya RESULT_CANCELED ile ActivityResult alır. NullPointerException’ı önlemek için kullanmadan önce sonucu her zaman null açısından kontrol edin.
Uygulamanız sık sık benzer senaryolar başlatıyorsa — örneğin, bir kişi seçip ad ve telefon döndürmek — özel bir Contract oluşturun. Bu, kod okunabilirliğini artırır ve başlatma ve sonuç işleme mantığında merkezi değişikliklere olanak tanır.
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) }
}
Sıkça Sorulan Sorular
Hayır — ActivityResultLauncher kayıt için bir Activity veya Fragment bağlamı gerektirir. ViewModel’i yalnızca durum depolamak için kullanın ve launcher’ı Activity veya Fragment’te oluşturup sonucu ViewModel’e iletin.
Activity Result API, activity-ktx 1.2.0 kütüphanesinden itibaren kullanılabilir. Minimum SDK API Level 14’tür (Android 4.0), ancak çoğu kontrat yalnızca API Level 19+’da çalışır.
İlk işlem tamamlanmadan önce launch’ın tekrarlanan çağrısı yok sayılır. Activity Result API paralel başlatmaları desteklemez — yeni bir çağrı yapmadan önce ilk işlemden callback bekleyin.
Geçiş, startActivityForResult çağrısını uygun Contract ile registerForActivityResult ile değiştirerek yapılır. onActivityResult’u kaldırın ve sonucu launcher callback’inde işleyin. Google, Android Developers belgelerinde bir geçiş kılavuzu sağlar.
Evet, birçok kütüphane ActivityResultContracts aracılığıyla entegrasyonu destekler. Örneğin, ML Kit Barcode Scanner, tarayıcıyı başlatmak için StartIntentSenderForResult kullanır. Belirli kütüphanenin belgelerini kontrol edin.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun