Back Press Handling — adalah mekanisme untuk mencegat dan memproses tombol sistem “Kembali” di Android, yang menentukan tindakan apa yang dilakukan saat ditekan. Menurut Android Developers (2024), mulai Android 11 metode tradisional onBackPressed() telah digantikan oleh OnBackPressedDispatcher. API baru memungkinkan komponen di setiap level hierarki untuk mencegat tekanan, bukan hanya Activity. Perbedaan utama — dukungan untuk banyak callback dalam rantai dengan prioritas.
Poin Penting
Back Press Handling — adalah mekanisme sistem Android yang menentukan apa yang terjadi ketika pengguna menekan tombol hardware atau software “Kembali”. Tergantung pada konteksnya, tekanan dapat: menutup layar saat ini dan kembali ke layar sebelumnya, menyembunyikan keyboard, menutup Drawer atau Bottom Sheet, keluar dari aplikasi jika pengguna berada di layar utama.
Perilaku tombol “Kembali” telah berevolusi dengan setiap versi Android. Di Android 10 muncul gesture navigasi, di Android 11 — OnBackPressedDispatcher sebagai API standar, dan di Android 13 — dukungan yang ditingkatkan untuk predictive back gesture, di mana sistem menunjukkan animasi transisi sebelum tindakan benar-benar dilakukan. Google secara konsisten bergerak menuju perilaku Back Press yang dapat diprediksi dan konsisten di semua perangkat.
Pemrosesan tombol “Kembali” yang benar — elemen UX yang kritis dalam aplikasi Android. Pengguna berharap bahwa tekanan “Kembali” akan membawanya kembali ke layar sebelumnya di tumpukan navigasi, bukan menutup aplikasi secara tiba-tiba. Pelanggaran harapan ini adalah salah satu penyebab utama ulasan negatif dan peringkat rendah di Google Play.
Sejarah Back Press API di Android mencerminkan evolusi umum platform: dari metode sederhana di Activity hingga sistem callback yang fleksibel dengan dukungan lifecycle dan Compose. Mari kita lihat tiga tahap pengembangan.
Sejak API Android pertama, tombol “Kembali” diproses dalam metode onBackPressed dari kelas Activity. Pengembang menimpa metode ini dan menulis logika sendiri. Masalahnya adalah Fragment dan View tidak dapat mencegat tekanan — semua kontrol melalui Activity. Ini menyebabkan Activity yang kembung dan rantai if-else yang rumit untuk menentukan siapa yang harus memproses tekanan.
Dengan Activity 1.0.0 (AndroidX) Google memperkenalkan OnBackPressedDispatcher. Ini adalah dispatcher pusat yang menerima callback dari komponen mana pun — Activity, Fragment, Dialog, View kustom. Callback didaftarkan dengan menentukan urutan (melalui priority) dan dapat ditambahkan atau dihapus secara dinamis. OnBackPressedDispatcher dipanggil lebih awal dari onBackPressed lama, memungkinkan tekanan dicegat sebelum Activity memprosesnya.
Android 13 memperkenalkan predictive back gesture — animasi sistem yang menunjukkan ke mana tekanan “Kembali” akan mengarah, bahkan sebelum pengguna menyelesaikan gesture. Untuk mendukung animasi ini, pengembang harus menggunakan OnBackPressedDispatcher dan menunjukkan apakah callback mendukung animasi sistem melalui properti isEnabled. Jika callback tidak mendukung predictive animation, sistem menampilkan animasi default yang mungkin tidak sesuai dengan konteks aplikasi.
| API | SDK Minimal | Dukungan Fragment | Predictive Back |
|---|---|---|---|
| onBackPressed | API Level 1 | Melalui Activity | Tidak |
| OnBackPressedDispatcher | Activity 1.0.0 | Langsung | Sebagian |
| OnBackPressedDispatcher + lifecycle | Activity 1.3.0 | Lifecycle-aware | Penuh |
OnBackPressedDispatcher — adalah inti dari Back Press API baru. Ini mengelola rantai callback, memanggilnya secara berurutan hingga yang pertama memproses peristiwa. Jika tidak ada callback yang memproses tekanan, dispatcher menjalankan tindakan default — memanggil finish() untuk Activity atau popBackStack() untuk Navigation Component.
Callback didaftarkan melalui addCallback dengan menentukan LifecycleOwner dan objek OnBackPressedCallback. Callback berisi properti isEnabled — jika disetel ke false, callback dilewati. Untuk priority dapat diberikan nilai dari 0 (terendah) hingga Integer.MAX_VALUE. Fragment Activity Result API menggunakan mekanisme ini untuk pendaftaran otomatis callback yang terikat siklus hidup.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val callback = object : OnBackPressedCallback(enabled = true) {
override fun handleOnBackPressed() {
if (isDrawerOpen) { closeDrawer() }
else { isEnabled = false; onBackPressed() }
}
}
onBackPressedDispatcher.addCallback(this, callback)
}
Callback secara otomatis dihapus ketika LifecycleOwner beralih ke status DESTROYED. Ini memecahkan masalah lama kebocoran callback saat rotasi layar. Jika callback ditambahkan ke Fragment, callback dijamin akan dihapus saat Fragment dihancurkan. Untuk menonaktifkan sementara callback, gunakan properti isEnabled — dapat diubah tanpa menghapus dan mendaftar ulang.
Urutan pemanggilan kebalikan dari urutan penambahan: callback yang ditambahkan terakhir mendapatkan kontrol pertama. Ini logis karena elemen UI yang paling dalam (misalnya Bottom Sheet di dalam Fragment) harus memproses tekanan lebih awal daripada Fragment induk. Jika callback terdalam tidak memproses tekanan (isEnabled = false), kontrol diteruskan ke berikutnya dalam rantai.
Fragment API menyediakan integrasinya sendiri dengan OnBackPressedDispatcher melalui metode requireActivity().onBackPressedDispatcher. Mulai Fragment 1.2.0, setiap Fragment dapat mendaftarkan callback sendiri yang secara otomatis terikat ke siklus hidup Fragment dan dihapus saat dihancurkan.
Pendaftaran callback di Fragment dilakukan di onCreate, onViewCreated, atau bahkan di View itu sendiri — yang penting hanya LifecycleOwner (Fragment) aktif. Ketika Fragment beralih ke status STARTED, callback diaktifkan, saat STOPPED — dinonaktifkan. Ini menjamin bahwa Fragment tersembunyi (di ViewPager) tidak akan memproses tekanan “Kembali”.
class EditorFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val callback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
showDiscardDialog()
}
}
requireActivity().onBackPressedDispatcher.addCallback(this, callback)
}
}
Dialog dan BottomSheet secara otomatis mencegat tekanan “Kembali” untuk ditutup. Jika Anda perlu melakukan tindakan tambahan sebelum menutup — daftarkan callback dengan prioritas lebih tinggi. Penting: jika Anda menyetel setCancelable(false) pada Dialog, callback tidak akan berfungsi — ini adalah perilaku sistem.
Jetpack Compose menyediakan API deklaratif untuk memproses tombol “Kembali” melalui fungsi composable BackHandler. BackHandler menerima enabled (nilai boolean) dan onBack — callback yang dipanggil saat ditekan. Jika enabled = false, tekanan diteruskan lebih lanjut dalam rantai.
BackHandler secara otomatis mendaftarkan OnBackPressedCallback di OnBackPressedDispatcher Activity induk. Ini memperhitungkan siklus hidup composable: saat keluar dari komposisi, callback dihapus. enabled dapat dikaitkan dengan status — misalnya, menampilkan dialog konfirmasi hanya jika ada perubahan yang belum disimpan di formulir.
@Composable
fun EditScreen(hasUnsavedChanges: Boolean) {
BackHandler(enabled = hasUnsavedChanges) {
// Tampilkan dialog konfirmasi
}
Column {
TextField(value = ..., onValueChange = ...)
}
}
Predictive back gesture di Compose didukung mulai Compose 1.5.0. BackHandler secara otomatis menangani animasi transisi sistem jika diaktifkan di perangkat. Untuk animasi predictive kustom, gunakan pengubah predictiveBackHandler, yang mengembalikan kemajuan gesture dari 0 hingga 1.
Back Press Handling terlihat sederhana, tetapi dalam praktiknya pengembang melakukan serangkaian kesalahan sistematis. Mari kita lihat masalah paling umum dan cara mengatasinya berdasarkan rekomendasi Google dan pengalaman komunitas.
Pemanggilan langsung finish() di handleOnBackPressed dapat menyebabkan keluar tak terduga dari aplikasi jika ada layar latar di tumpukan navigasi. Selalu periksa NavController.backStack melalui Navigation Component atau Coordinator sebelum menutup Activity.
Jika Anda mendaftarkan callback tanpa LifecycleOwner (menggunakan addCallback lama tanpa parameter), callback akan hidup selamanya dan dapat menyebabkan NullPointerException jika Activity sudah dihancurkan. Selalu gunakan addCallback(this, callback) dengan LifecycleOwner.
Untuk jendela modal (Bottom Sheet, Dialog) selalu setel isEnabled = true hanya saat jendela terlihat. Gunakan addCallback dengan lambda yang memeriksa status jendela. Navigation Component secara otomatis mengelola ini untuk NavHost.
Tekanan ganda cepat pada “Kembali” dapat menyebabkan pemanggilan ganda finish(). Gunakan flag atau throttleLast untuk perlindungan terhadap panggilan berulang dalam 500 ms. Navigation Component menangani situasi ini secara bawaan, tetapi dalam skenario kustom Anda perlu mengimplementasikan perlindungan secara manual.
private var lastBackPressTime = 0L
override fun handleOnBackPressed() {
val currentTime = System.currentTimeMillis()
if (currentTime - lastBackPressTime > 500) {
lastBackPressTime = currentTime
navigateBack()
}
}
Pertanyaan Umum
onBackPressed menjadi tidak digunakan lagi (deprecated) di Android 11 karena hanya berfungsi di tingkat Activity. OnBackPressedDispatcher memungkinkan komponen mana pun (Fragment, Dialog, View) untuk mencegat tekanan melalui mekanisme terpadu dengan dukungan siklus hidup.
Sistem Android mengubah gesture gesek dari tepi menjadi tekanan sistem “Kembali” sebelum aplikasi menerimanya. Di tingkat OnBackPressedDispatcher Anda tidak dapat membedakan kedua peristiwa ini — keduanya datang sebagai handleOnBackPressed.
Ya, pemrosesan OnBackPressedDispatcher sama untuk perangkat dengan tiga tombol dan dengan navigasi gesture. Kode pencegat tidak tergantung pada jenis navigasi — sistem sendiri mengubah gesture menjadi panggilan dispatcher.
Aktifkan predictive back di Developer Options emulator Android 13+. Gunakan ADB: `adb shell settings put global enable_back_animation 1`. Setelah diaktifkan, animasi sistem akan menunjukkan pratinjau transisi saat menekan “Kembali”.
Periksa dua kondisi: LifecycleOwner harus dalam status STARTED atau RESUMED, dan isEnabled callback harus true. Jika kedua kondisi terpenuhi, pastikan callback ditambahkan ke OnBackPressedDispatcher yang benar — gunakan requireActivity().onBackPressedDispatcher di Fragment.
Ringkasan
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