ActivityResultLauncher adalah komponen Android Activity Result API, yang diperkenalkan dalam versi Activity 1.2.0 dari pustaka androidx.activity. Ini menggantikan metode usang startActivityForResult dan onActivityResult, yang telah menjadi bagian dari Android SDK sejak awal pembuatannya. Menurut Android Developers (2024), API baru ini menghilangkan masalah pengikatan ketat dengan Activity dan kurangnya keamanan tipe. ActivityResultLauncher didaftarkan sebelumnya dan menggunakan Contract untuk pengetikan ketat data masukan dan keluaran.
Poin Utama
ActivityResultLauncher adalah kelas dari paket androidx.activity.result yang menyediakan mekanisme aman tipe untuk meluncurkan Activity dan menerima hasilnya. Launcher dibuat melalui metode registerForActivityResult yang menerima dua parameter: Contract (mendeskripsikan tipe masukan dan keluaran) dan ActivityResultCallback (pemroses hasil). Setelah pendaftaran, launcher siap dipanggil melalui metode launch.
Perbedaan utama dari API lama adalah pemisahan pendaftaran dan peluncuran. Pendaftaran dilakukan pada tahap inisialisasi (Activity.onCreate atau Fragment.onCreate), callback diikat ke launcher satu kali dan dijamin akan terpicu saat hasil kembali. Ini menghilangkan masalah ketika onActivityResult terpicu dalam urutan yang tidak terduga atau pada Activity yang sudah dihancurkan.
ActivityResultLauncher mendukung semua skenario yang sebelumnya ditangani melalui onActivityResult: meluncurkan kamera, galeri, permintaan kontak, izin, dan Activity kustom. Selain itu, API dapat diperluas: pengembang dapat membuat Contract kustom untuk skenario pertukaran data spesifik antar Activity.
startActivityForResult telah menjadi bagian dari Android SDK sejak versi API Level 1 (2008) dan tetap menjadi cara utama untuk mendapatkan hasil dari Activity selama lebih dari 12 tahun. Namun, metode ini memiliki kekurangan mendasar yang diperbaiki Google dalam Activity Result API. Mari kita lihat masalah utama dan bagaimana API baru menyelesaikannya.
Metode startActivityForResult terikat dengan Activity dan Fragment melalui requestCode — bilangan bulat sembarang yang diteruskan ke onActivityResult. Pengembang secara manual mencocokkan kode dengan operasi yang diluncurkan, yang menyebabkan kesalahan saat menggunakan kembali kode dan pewarisan. ActivityResultLauncher sepenuhnya menghilangkan requestCode: callback diikat ke launcher tertentu pada tahap pendaftaran dan hanya dipanggil untuknya.
Pada perubahan konfigurasi (rotasi layar, perubahan bahasa) Activity dibuat ulang dan onActivityResult mungkin tidak terpicu — callback hilang. Activity Result API secara otomatis menyimpan dan memulihkan status launcher melalui SavedStateRegistry, yang menjamin penerimaan hasil bahkan setelah pembuatan ulang Activity.
API lama mengirimkan hasil melalui Intent dengan Bundle, di mana kunci dan tipe data tidak diperiksa oleh kompiler. Activity Result API menggunakan Contract — antarmuka generik yang menentukan tipe data masukan (I) dan tipe hasil (O). Kesalahan ketidakcocokan tipe terdeteksi pada tahap kompilasi, bukan saat runtime.
| Karakteristik | startActivityForResult | ActivityResultLauncher |
|---|---|---|
| RequestCode | Memerlukan pengelolaan manual | Otomatis, tidak diperlukan |
| Keamanan tipe | Tidak | Generic Contract |
| Penyimpanan saat rotasi | Hilang | SavedStateRegistry |
| API minimal | API Level 1 | Activity 1.2.0 |
| Penggunaan di Compose | Tidak didukung | rememberLauncherForActivityResult |
Contract adalah antarmuka ActivityResultContract<I, O> yang menentukan cara meluncurkan Activity dan cara menafsirkan hasilnya. Google menyediakan serangkaian kontrak bawaan untuk skenario umum yang mencakup sebagian besar kebutuhan pengembang.
StartIntentSenderForResult adalah kontrak dasar untuk meluncurkan IntentSender. Digunakan dalam skenario sistem, misalnya saat otentikasi melalui Google Sign-In atau pembayaran melalui Google Pay. Parameter masukan — PendingIntent, keluaran — ActivityResult dengan kode dan Intent.
RequestMultiplePermissions adalah kontrak untuk meminta beberapa izin sekaligus di Android 6.0+. Parameter masukan — array String dengan nama izin, keluaran — Map<String, Boolean> dengan hasil setiap permintaan. Sebelumnya, ini memerlukan penguraian manual di onRequestPermissionsResult dengan pencocokan kode permintaan.
TakePicture adalah kontrak untuk mengambil foto melalui kamera sistem. Masukan — Uri tempat menyimpan foto, keluaran — Boolean (berhasil). TakeVideo bekerja serupa dengan video. Kontrak ini menggantikan MediaStore.ACTION_IMAGE_CAPTURE yang usang dengan perilaku tidak stabil di berbagai perangkat.
GetContent adalah kontrak untuk memilih konten melalui pemilih sistem. Masukan — tipe MIME (misalnya image/*), keluaran — Uri file yang dipilih. OpenDocument berbeda dengan dukungan pemilihan ganda dan pemfilteran berdasarkan jenis dokumen. Kedua kontrak bekerja melalui SAF (Storage Access Framework).
CreateDocument adalah kontrak untuk membuat dokumen baru melalui dialog sistem. Pengguna memilih nama dan folder, sistem mengembalikan Uri untuk menulis. OpenDocumentTree memberikan akses ke seluruh direktori — pengguna memilih folder, dan aplikasi menerima tree-uri untuk membaca dan menulis semua file di dalamnya.
Pola dasar penggunaan ActivityResultLauncher di Android klasik terdiri dari dua langkah: pendaftaran melalui registerForActivityResult pada tahap inisialisasi dan pemanggilan launch sebagai respons terhadap tindakan pengguna. Mari kita lihat contoh umum pemilihan gambar dari galeri.
Daftarkan launcher di onCreate Activity — ini menjamin bahwa callback akan siap sebelum setiap kemungkinan pemanggilan. Jangan pernah mendaftarkan launcher tepat sebelum peluncuran — ini melanggar kontrak API dan dapat menyebabkan kehilangan hasil saat pembuatan ulang 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/*")
}
}
Di Fragment, pendaftaran dilakukan di onCreate, onAttach, atau inisialisasi di onCreateView. FragmentActivity meneruskan launcher melalui Activity induk, sehingga hasilnya diproses di dalam Fragment, bukan di Activity. Ini meningkatkan enkapsulasi dibandingkan dengan onActivityResult, di mana semua hasil dari semua Fragment dikumpulkan dalam satu metode Activity.
class ProfileFragment : Fragment() {
private val cameraLauncher =
registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
if (success) { updateProfilePhoto() }
}
fun takePhoto(photoUri: Uri) {
cameraLauncher.launch(photoUri)
}
}
Jetpack Compose menyediakan fungsionalitas composable khusus untuk Activity Result API — rememberLauncherForActivityResult. Tidak seperti pendekatan klasik, di Compose launcher dibuat sebagai objek yang terikat ke siklus hidup composable melalui remember. Ini memungkinkan penggunaan Activity Result API secara deklaratif penuh tanpa akses langsung ke Activity atau Fragment.
rememberLauncherForActivityResult menerima Contract dan callback, mengembalikan ActivityResultLauncher. Launcher dipertahankan saat rekomposisi dan dibersihkan secara otomatis saat keluar dari komposisi. Pemanggilan launch terjadi sebagai respons terhadap peristiwa — misalnya, klik tombol atau perubahan status.
@Composable
fun PhotoPicker() {
val context = LocalContext.current
val launcher = rememberLauncherForActivityResult(
ActivityResultContracts.GetContent()
) { uri -> handleImage(uri) }
Button(onClick = { launcher.launch("image/*") }) {
Text("Pilih Foto")
}
}
Permintaan izin di Compose juga dilakukan melalui rememberLauncherForActivityResult dengan kontrak RequestPermission atau RequestMultiplePermissions. Google merekomendasikan penggunaan accompanist-permissions, tetapi di balik layar juga menggunakan Activity Result API. Untuk mengontrol status izin, nyaman untuk menyimpan status di remember atau ViewModel.
Activity Result API telah menghilangkan banyak masalah dari pendekatan lama, tetapi penggunaannya yang tidak tepat dapat menyebabkan jenis kesalahan baru. Mari kita lihat masalah paling umum dan cara menghindarinya.
Pendaftaran launcher harus dilakukan saat inisialisasi komponen — di onCreate Activity atau penginisialisasi Fragment. Jika Anda mendaftarkan launcher di dalam lambda, callback, atau coroutine, saat pembuatan ulang Activity pendaftaran dapat dilakukan lagi, dan launcher lama akan kehilangan koneksi dengan hasilnya.
Setiap launcher mendapatkan kunci unik untuk menyimpan status. Jika Anda mendaftarkan dua launcher dengan Contract yang sama dalam satu komponen, SavedStateRegistry dapat menimpa status satu dengan yang lain. Android Studio memperingatkan tentang ini melalui aturan lint UnnecessaryRegisterForActivityResult, tetapi lebih baik mengontrol keunikan secara manual.
Pengguna dapat membatalkan tindakan — menekan tombol kembali sistem, meminimalkan aplikasi, atau beralih ke aplikasi lain. Dalam kasus ini, callback akan menerima null atau ActivityResult dengan RESULT_CANCELED. Selalu periksa hasil untuk null sebelum digunakan untuk menghindari NullPointerException.
Jika aplikasi Anda sering meluncurkan skenario serupa — misalnya, memilih kontak dengan mengembalikan nama dan telepon — buat Contract Anda sendiri. Ini meningkatkan keterbacaan kode dan memungkinkan perubahan terpusat pada logika peluncuran dan penanganan hasil.
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) }
}
Pertanyaan yang sering diajukan
Tidak — ActivityResultLauncher memerlukan konteks Activity atau Fragment untuk pendaftaran. Gunakan ViewModel hanya untuk menyimpan status, dan buat launcher di Activity atau Fragment dan teruskan hasilnya ke ViewModel.
Activity Result API tersedia mulai dari pustaka activity-ktx 1.2.0. SDK minimal — API Level 14 (Android 4.0), tetapi sebagian besar kontrak hanya berfungsi pada API Level 19+.
Pemanggilan ulang launch sebelum operasi pertama selesai akan diabaikan. Activity Result API tidak mendukung peluncuran paralel — tunggu callback dari operasi pertama sebelum pemanggilan baru.
Migrasi dilakukan dengan mengganti pemanggilan startActivityForResult dengan registerForActivityResult dengan Contract yang sesuai. Hapus onActivityResult dan tangani hasilnya di callback launcher. Google menyediakan panduan migrasi di dokumentasi Android Developers.
Ya, banyak pustaka mendukung integrasi melalui ActivityResultContracts. Misalnya, ML Kit Barcode Scanner menggunakan StartIntentSenderForResult untuk meluncurkan pemindai. Periksa dokumentasi pustaka tertentu.
Kesimpulan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga