onPause — metode siklus hidup Android yang dipanggil ketika Activity kehilangan fokus input, tetapi tetap terlihat sebagian di layar. Sistem memanggil onPause sebelum Activity baru muncul ke latar depan, saat membuka kotak dialog, saat menekan tombol “Aplikasi Terbaru”, atau saat panggilan masuk. Metode ini — titik terakhir yang dijamin untuk menyimpan data pengguna, karena setelah onStop dan onDestroy sistem dapat mengakhiri proses tanpa panggilan tambahan. Di dalam onPause, pengembang menyimpan draf, menjeda animasi, melepaskan kamera, dan menulis status UI saat ini ke SharedPreferences. Detail tentang siklus hidup Activity lengkap baca di artikel Activity Lifecycle.
Poin Utama
onPause — metode keempat siklus hidup Activity yang dipanggil ketika layar kehilangan fokus input, tetapi tetap terlihat sebagian bagi pengguna. Ini adalah keadaan “transisi” antara kerja aktif aplikasi dan penyembunyiannya. Sistem memanggil onPause dalam skenario berikut: membuka Activity lain (layar baru menutupi yang saat ini), munculnya kotak dialog (Dialog, PopupWindow, Snackbar tidak memanggil onPause, tetapi DialogFragment memanggil), menekan tombol “Aplikasi Terbaru”, panggilan masuk, menekan tombol “Daya” untuk mengunci layar.
Tugas utama onPause — mempersiapkan aplikasi untuk kemungkinan disembunyikan atau dihancurkan. Ini adalah titik terakhir dalam siklus hidup di mana pengembang dapat yakin bahwa kodenya akan dijalankan sebelum sistem melanjutkan transisi ke komponen lain. Setelah onPause, sistem memanggil onStop (jika Activity disembunyikan sepenuhnya), setelah itu penghancuran proses dapat terjadi kapan saja tanpa pemberitahuan tambahan.
Menurut dokumentasi Android Developers (2025), onPause harus seringan dan secepat mungkin. Selama onPause belum mengembalikan kendali, sistem tidak dapat memulai Activity berikutnya — ini berarti pengguna melihat keterlambatan transisi antar layar. Google merekomendasikan untuk menyelesaikan onPause dalam kurang dari 100 milidetik, dan semua operasi panjang (penyimpanan ke database, penulisan ke disk) dilakukan secara asinkron melalui coroutine atau apply().
Di Activity, metode onPause dipanggil setiap kali layar berhenti aktif, tetapi mungkin masih dapat ditampilkan sebagian. Contoh tipikal: pengguna membuka aplikasi “Peta”, menekan “Bagikan Lokasi”, dan di atas Peta terbuka dialog sistem pemilihan aplikasi. Activity Peta mendapatkan onPause, tetapi tetap terlihat di bawah dialog. Saat dialog ditutup, Peta mendapatkan onResume tanpa panggilan onStart (layar tidak disembunyikan sepenuhnya).
class NoteEditorActivity : AppCompatActivity() {
private var binding: ActivityNoteEditorBinding? = null
private val prefs by lazy {
getSharedPreferences("note_drafts", Context.MODE_PRIVATE)
}
override fun onPause() {
super.onPause()
// Menyimpan draf catatan — asinkron
prefs.edit()
.putString("draft_title", binding?.titleInput?.text.toString())
.putString("draft_body", binding?.bodyInput?.text.toString())
.putLong("draft_timestamp", System.currentTimeMillis())
.apply()
// Menjeda video
binding?.videoPlayer?.pause()
// Melepaskan sumber daya eksklusif
releaseCamera()
releaseAudioFocus()
}
override fun onResume() {
super.onResume()
// Memulihkan draf
binding?.titleInput?.setText(prefs.getString("draft_title", ""))
binding?.bodyInput?.setText(prefs.getString("draft_body", ""))
acquireCamera()
acquireAudioFocus()
}
}
Contoh NoteEditorActivity menunjukkan kerja yang benar dengan onPause: menyimpan draf di SharedPreferences melalui apply(), menjeda file video, melepaskan kamera dan fokus audio. Setiap panggilan — ringan dan cepat, tidak memblokir utas UI cukup untuk ANR. Perhatikan urutan: super.onPause() dipanggil di baris pertama — ini menjamin bahwa logika sistem akan dijalankan bahkan saat terjadi eksepsi di kode pengguna.
onPause — titik terakhir di mana pengembang dapat menyimpan data pengguna secara dijamin sebelum aplikasi disembunyikan atau dihentikan oleh sistem. Setelah onStop, sistem dapat menghancurkan proses saat kekurangan memori tanpa memanggil onDestroy. Metode onSaveInstanceState() dipanggil setelah onPause, tetapi Bundle-nya tidak ditujukan untuk penyimpanan jangka panjang — hanya hidup hingga onCreate berikutnya.
SharedPreferences dengan apply() asinkron — cara optimal untuk menyimpan data volume kecil di onPause. Berbeda dengan commit(), yang secara sinkron menulis data ke disk dan mengembalikan boolean, apply() segera menyimpan data di memori dan menjadwalkan penulisan asinkron ke disk. Ini memakan waktu kurang dari 1 milidetik di utas UI dibandingkan 10–100 milidetik untuk commit().
override fun onPause() {
super.onPause()
// ❌ Buruk: penulisan sinkron memblokir utas
// prefs.edit().putInt("score", score).commit()
// ✅ Baik: penulisan asinkron
prefs.edit().putInt("score", score).apply()
// Untuk objek kompleks — caching di ViewModel
viewModel.saveState()
}
Untuk data terstruktur (SQLite melalui Room) di onPause digunakan coroutine dengan lifecycleScope. ViewModelScope secara otomatis membatalkan coroutine saat ViewModel dihancurkan, mencegah penulisan ke database yang ditutup. Penulisan melalui Room dengan coroutine memakan waktu 5–15 milidetik dan tidak memblokir utas UI.
// Di ViewModel:
fun saveDraft(title: String, body: String) {
viewModelScope.launch(Dispatchers.IO) {
noteDao.insert(NoteDraft(title = title, body = body))
}
}
// Di Activity.onPause:
viewModel.saveDraft(
binding?.titleInput?.text.toString(),
binding?.bodyInput?.text.toString()
)
onPause di Fragment dipanggil ketika Fragment berhenti aktif, tetapi mungkin tetap terlihat. Ini terjadi ketika: Fragment digantikan oleh Fragment lain melalui FragmentTransaction; Fragment berhenti menjadi halaman saat ini di ViewPager; Activity yang mengandung Fragment mendapatkan onPause. Interaksi antara onPause Activity dan onPause Fragment bersifat hierarkis ketat: pertama Activity mendapatkan onPause, kemudian semua Fragment-nya.
class MapFragment : Fragment() {
private var mapController: MapController? = null
override fun onPause() {
super.onPause()
mapController?.stopFollowMode()
binding?.mapContainer?.alpha = 0.7f
}
override fun onResume() {
super.onResume()
binding?.mapContainer?.alpha = 1.0f
if (isVisible) {
mapController?.startFollowMode()
}
}
}
Spesifik bekerja dengan peta di onPause: Google Maps dan Yandex Maps mengonsumsi sumber daya GPU yang signifikan dalam mode pelacakan aktif (follow mode). Saat kehilangan fokus, masuk akal untuk menonaktifkan animasi peta dan mengurangi frekuensi pembaruan marker, dan saat fokus kembali — memulihkan fungsionalitas penuh. Ini meningkatkan kinerja dan mengurangi konsumsi daya saat beralih antar layar.
Salah satu kebingungan paling umum di kalangan pengembang Android pemula — tidak memahami perbedaan antara onPause dan onStop. Mari kita bahas setiap skenario dan tentukan metode yang benar.
| Skenario | onPause | onStop |
|---|---|---|
| Membuka kotak dialog | Dipanggil | Tidak dipanggil |
| Membuka Activity baru (tidak transparan) | Dipanggil | Dipanggil |
| Menekan tombol “Beranda” | Dipanggil | Dipanggil |
| Mengunci layar | Dipanggil | Dipanggil |
| Panggilan masuk | Dipanggil | Dipanggil |
| Activity transparan di atas yang saat ini | Dipanggil | Tidak dipanggil |
| Split Screen (setengah layar) | Dipanggil | Tidak dipanggil |
| PiP (Picture-in-Picture) | Dipanggil | Tidak dipanggil |
Aturan utama: onPause dipanggil pada setiap kehilangan fokus, onStop — hanya pada kehilangan visibilitas penuh. Jika Activity tetap terlihat (bahkan sebagian), onStop tidak dipanggil. Ini sangat penting untuk mode Split Screen, PiP, dan Activity transparan — di sini onPause/onResume berfungsi, tetapi onStart/onStop tidak.
onPause — metode yang paling kritis waktu dalam siklus hidup, karena memblokir rendering Activity berikutnya. Sistem menunggu penyelesaian onPause Activity saat ini sebelum menampilkan yang baru. Jika onPause berjalan lebih dari 100 milidetik, pengguna melihat keterlambatan transisi; jika lebih dari 5 detik — sistem menampilkan ANR.
Panduan Kinerja Android Google (2025) memberikan rekomendasi berikut untuk onPause: jangan lakukan permintaan jaringan — harus dibatalkan atau dipindahkan ke WorkManager; jangan tulis file besar ke disk — gunakan BufferedWriter di utas latar belakang; jangan lakukan kueri SQL kompleks — operasi Room harus asinkron melalui coroutine; hindari membuat objek baru — garbage collection di onPause memperburuk keterlambatan; gunakan apply() alih-alih commit() untuk SharedPreferences.
override fun onPause() {
super.onPause()
// ❌ Buruk: permintaan HTTP memblokir UI
// val response = api.syncSave(data).execute()
// ❌ Buruk: penulisan sinkron ke file
// FileOutputStream(file).write(data)
// ✅ Baik: penyimpanan asinkron
lifecycleScope.launch {
withContext(Dispatchers.IO) {
api.saveData(data)
fileDao.write(data)
}
}
// ✅ Baik: penulisan ringan ke SharedPreferences
prefs.edit().putString("key", value).apply()
}
Profiling onPause melalui Android Studio Profiler (grafik CPU) menunjukkan waktu eksekusi yang tepat. Jika onPause memakan waktu lebih dari 100 ms, Profiler menyorot metode dengan warna kuning, dan lebih dari 500 ms — merah. Di proyek komersial IT Sectr, kami menggunakan tes Macrobenchmark yang secara otomatis memeriksa waktu transisi antar Activity dan memberi sinyal regresi kinerja di pipeline CI.
Bahkan pengembang berpengalaman pun membuat kesalahan di onPause. Mari kita bahas lima masalah tipikal dan solusinya.
Pemanggilan Room DAO dengan kueri sinkron (.executeAsObservable() tanpa coroutine) di onPause memblokir utas UI selama 10–50 md. Jika pada saat itu terjadi GC atau persaingan untuk menulis ke database, keterlambatan bisa mencapai 200–500 md. Solusi: gunakan coroutine dengan Dispatchers.IO atau apply() untuk SharedPreferences.
onPause bukan tempat untuk mendaftarkan pendengar. Jika Anda mendaftarkan BroadcastReceiver di onPause, ia akan tetap aktif ketika Activity sudah tidak terlihat. Pendaftaran hanya boleh dilakukan di onStart/onResume, dan di onPause/onStop — hanya pembatalan pendaftaran. Pengecualian — API Intent-driven yang memerlukan pendaftaran sebelum pemanggilan.
Jika di onPause terjadi eksepsi yang tidak tertangani, sistem tidak memanggil onStop dan onDestroy. Activity macet dalam keadaan tidak menentu, dan onResume saat kembali mungkin tidak memulihkan sumber daya yang telah dilepaskan dengan benar. Solusi: bungkus operasi kritis dalam try/catch dengan pencatatan melalui Log.e().
Tidak perlu menyimpan di onPause data yang mudah dipulihkan. Misalnya, hasil permintaan API di-cache di Room atau DataStore saat diterima, bukan di onPause. Simpan hanya apa yang dimasukkan pengguna secara manual dan tidak dapat dipulihkan secara otomatis — teks di kolom, elemen yang dipilih, posisi scroll.
super.onPause() harus dipanggil, tetapi tidak seperti onCreate, ketiadaannya tidak menyebabkan crash langsung. Sistem “maafkan” melewatkan super di onPause, tetapi mesin status internal masuk ke keadaan yang salah. Panggilan onResume berikutnya mungkin tidak memulihkan fokus input, dan Activity tetap “beku”. Selalu panggil super.onPause() sedini mungkin.
Pertanyaan yang Sering Diajukan
Pemanggilan finish() di onPause akan mengakhiri Activity segera setelah kembali dari metode. Ini adalah skenario yang benar jika saat kehilangan fokus layar harus ditutup (misalnya, layar otorisasi saat aplikasi diminimalkan). Namun, finish() memulai siklus penyelesaian penuh: onStop → onDestroy, yang menambah keterlambatan pada transisi. Gunakan finish() di onPause hanya ketika benar-benar diperlukan.
onPause — untuk menyimpan data yang harus bertahan dari penghentian proses (draf di SharedPreferences/Room). onSaveInstanceState — untuk menyimpan status UI sementara yang hanya diperlukan hingga onCreate berikutnya (posisi scroll, tab yang dipilih). Bundle onSaveInstanceState tidak disimpan saat aplikasi dihentikan sepenuhnya — hanya ada di memori. Data onPause disimpan di disk dan bertahan dari restart.
Tidak disarankan. Membuka dialog atau jendela pop-up di onPause menyebabkan WindowLeakException jika Activity sudah diakhiri. Jika perlu menampilkan notifikasi saat kehilangan fokus, gunakan NotificationManager (notifikasi sistem) — ini aman dan diharapkan oleh pengguna. Untuk tindakan tertunda, gunakan AlarmManager atau WorkManager.
onPause dijamin dipanggil sebelum Activity berhenti aktif. onStop mungkin tidak dipanggil jika sistem menghentikan proses untuk membebaskan memori — dalam hal ini onDestroy juga tidak dipanggil. onPause adalah satu-satunya metode setelah onResume yang selalu dipanggil, terlepas dari alasan kehilangan fokus. Oleh karena itu, semua data kritis disimpan tepat di onPause.
Untuk menguji onPause digunakan Robolectric atau FragmentScenario dari AndroidX Test. FragmentScenario.create() → moveToState(State.STARTED) → moveToState(State.RESUMED) → moveToState(State.STARTED) secara sekuensial memanggil onPause. Kemudian diperiksa apakah data telah disimpan di SharedPreferences atau apakah kamera telah dilepaskan melalui objek mock. Robolectric 4.12+ mendukung emulasi onPause/onResume tanpa perangkat fisik.
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