onDestroy: apa itu, penghentian Activity di Android

Penulis: IT Sectr Diterbitkan: 2026-03-04 Waktu membaca: 8 mnt

onDestroy — metode akhir siklus hidup Activity dan Fragment di Android, dipanggil sebelum penghancuran total komponen. onDestroy menandakan bahwa Activity atau Fragment mengakhiri kerjanya: semua sumber daya harus dibebaskan, fragment bersarang — dihancurkan, ViewModel — dibersihkan. Menurut data Google, onDestroy dipanggil dalam 100% kasus penghentian Activity, tetapi saat pembunuhan proses (process death) sistem dapat melewatkan panggilan onDestroy sepenuhnya. Dokumentasi Android tentang onDestroy menekankan bahwa metode ini tidak menjamin panggilan saat penghentian darurat.

Poin Utama

  • onDestroy — panggilan terakhir sebelum penghancuran Activity atau Fragment, ditujukan untuk pembersihan akhir sumber daya.
  • Panggilan onDestroy tidak dijamin saat pembunuhan proses oleh sistem (process death) — jangan andalkan untuk menyimpan data kritis.
  • Di onDestroy perlu membatalkan tugas latar belakang, menutup soket dan basis data, membersihkan ViewModelStore.
  • Perbedaan dari onStop: onStop — kehilangan visibilitas (Activity hidup di memori), onDestroy — penghancuran total.
  • isFinishing() di onDestroy menunjukkan apakah Activity berakhir atas perintah pengguna (finish()) atau keputusan sistem.

onDestroy: apa itu di Android?

onDestroy — metode callback yang dipanggil Android sebelum menghancurkan Activity atau Fragment secara final. Ini adalah kesempatan terakhir bagi pengembang untuk membebaskan sumber daya, membatalkan operasi latar belakang, dan mengakhiri pekerjaan dengan data. Setelah eksekusi onDestroy, instance Activity/Fragment ditandai untuk pengumpulan sampah (GC) dan tidak dapat digunakan lagi.

Alasan pemanggilan onDestroy:

  • Panggilan eksplisit finish() — pengguna menekan "Kembali" atau pengembang memanggil finishActivity().
  • Rotasi layar — Activity dihancurkan dan dibuat ulang dengan konfigurasi baru.
  • Perubahan konfigurasi — keyboard, perubahan bahasa, perubahan ukuran layar (multi-window).
  • Keputusan sistem — Android membunuh Activity untuk membebaskan sumber daya (tetapi onDestroy mungkin tidak dipanggil).

Menurut statistik Google Android Vitals (2025), sekitar 12% dari semua kasus penghancuran Activity disebabkan oleh rotasi layar, 65% oleh finish() dan 23% oleh perubahan konfigurasi. Persentase pembunuhan proses dengan melewatkan onDestroy adalah sekitar 5–8% tergantung pada perangkat dengan RAM kecil (kurang dari 4 GB).

Kapan onDestroy dipanggil — dan kapan tidak

onDestroy dipanggil dalam sebagian besar skenario standar, tetapi ada pengecualian penting yang harus diperhatikan pengembang. Memahami jaminan panggilan onDestroy sangat penting untuk arsitektur aplikasi, terutama untuk menyimpan data dan membatalkan tugas WorkManager.

Kapan onDestroy dipanggil:

  • Pengguna menekan tombol "Kembali" — Activity.finish() → onPause → onStop → onDestroy.
  • Rotasi layar — Activity dihancurkan (onPause → onStop → onDestroy), lalu dibuat ulang.
  • Perubahan konfigurasi — pengaturan sistem yang memerlukan pembuatan ulang Activity.
  • Panggilan finishAffinity() — mengakhiri semua Activity di tumpukan.
  • Penghapusan Fragment dari FragmentManager — Fragment menerima onPause → onStop → onDestroyView → onDestroy → onDetach.

Kapan onDestroy TIDAK dipanggil:

  • Pembunuhan proses oleh sistem (process death) — Android membunuh seluruh proses aplikasi saat kekurangan memori. Activity tidak menerima onDestroy karena proses dihentikan pada tingkat kernel Linux.
  • Penghentian darurat — pengecualian yang tidak tertangkap di thread utama membunuh aplikasi tanpa panggilan onDestroy.
  • Force Stop — pengguna menghentikan paksa aplikasi di pengaturan.

Karena tidak adanya jaminan panggilan onDestroy, Google merekomendasikan: jangan pernah mengandalkan onDestroy untuk menyimpan data kritis. Gunakan onSaveInstanceState(), WorkManager, atau Room dengan penyimpanan otomatis. onDestroy — untuk membebaskan sumber daya, bukan untuk persistensi.

onDestroy di Activity dan Fragment: persamaan dan perbedaan

onDestroy ada baik untuk Activity maupun Fragment, tetapi dengan kontrak yang berbeda. Pada Fragment, siklus hidup lebih detail: selain onDestroy ada onDestroyView (penghancuran hierarki View) dan onDetach (pemisahan dari Activity).

KomponenMetode penghancuranUrutanViewModel bertahan
ActivityonDestroyonPause → onStop → onDestroyTidak (hanya jika ViewModelStore tidak disimpan)
FragmentonDestroyView, onDestroy, onDetachonPause → onStop → onDestroyView → onDestroy → onDetachYa, jika Fragment tidak dihapus

Perbedaan utama: pada Fragment, View dibuat ulang lebih sering daripada Fragment itu sendiri. Saat rotasi layar, Fragment melalui onDestroyView (penghancuran View), tetapi Fragment itu sendiri dan ViewModel-nya tetap hidup. onDestroyView — tempat yang tepat untuk membersihkan referensi ke View untuk menghindari kebocoran memori. onDestroy Fragment — analog dengan onDestroy Activity, dipanggil saat penghapusan total Fragment.

Fragment bersarang (child fragments) dihancurkan sebelum onDestroy Fragment induk. Di Activity, fragment anak menerima onDestroy saat panggilan onDestroy Activity induk. Urutan dijamin: fragment berakhir lebih awal daripada Activity yang menampungnya.

Apa yang harus dilakukan di onDestroy: daftar periksa pembersihan

onDestroy ditujukan untuk membebaskan semua sumber daya yang tidak boleh hidup lebih lama dari Activity atau Fragment. Berbeda dengan onStop yang membebaskan sumber daya hingga kembali, onDestroy melakukan pembersihan akhir.

Daftar periksa tindakan wajib di onDestroy:

  • Pembatalan coroutine dan Flow — batalkan job yang tidak terikat ke viewModelScope. viewModelScope dibatalkan secara otomatis, tetapi lifecycleScope terikat ke siklus hidup Activity.
  • Penutupan soket dan saluran — WebSocket (OkHttp), BluetoothSocket, ServerSocket. Membiarkannya terbuka setelah penghancuran adalah kebocoran sumber daya sistem.
  • Penutupan file dan aliran — FileInputStream, FileOutputStream, Cursor. Cursor dapat menyebabkan ANR pada ContentProvider jika tidak ditutup.
  • Berhenti berlangganan dari ContentObserver — jika Activity memantau perubahan konten (kontak, media).
  • Berhenti berlangganan dari BroadcastReceiver — receiver yang terdaftar secara dinamis harus dibatalkan.
  • Penutupan basis data — Room menutup koneksi secara otomatis saat penghancuran Application, tetapi SQLiteDatabase langsung memerlukan close() manual.

Apa yang TIDAK boleh dilakukan di onDestroy: Jangan simpan data di onDestroy — gunakan onPause atau onSaveInstanceState. Jangan mulai Service atau tugas WorkManager baru — Activity akan dihancurkan dan Anda tidak dapat melacak hasilnya. Jangan mencoba memperbarui UI — hierarki View sudah dihancurkan atau dalam proses penghancuran; panggilan findViewById() akan mengembalikan null.

onDestroy dan ViewModel: kerja sama

ViewModel dirancang untuk bertahan dari onDestroy Activity saat rotasi layar, tetapi dihancurkan bersama Activity saat finish(). Perilaku asimetris ini — penyebab utama kebingungan di kalangan pengembang.

Saat rotasi layar:

  • Activity: onPause → onStop → onDestroy (Activity dihancurkan).
  • ViewModel: TIDAK dihancurkan — ViewModelStore disimpan dan diteruskan ke Activity baru.
  • Activity baru: onCreate → onStart → onResume, menerima ViewModel yang sama.

Saat finish() (pengguna menekan "Kembali"):

  • Activity: onPause → onStop → onDestroy.
  • ViewModel: onCleared() — dipanggil setelah onDestroy Activity.
  • Semua coroutine viewModelScope dibatalkan secara otomatis.

Oleh karena itu, pembatalan viewModelScope di onDestroy tidak diperlukan — ViewModel akan melakukannya sendiri. Jika Anda menggunakan lifecycleScope (terikat ke Activity, bukan ke ViewModel), batalkan di onDestroy melalui lifecycleScope.cancel() atau kelola Job secara manual.

Contoh kode dengan onDestroy di Kotlin

Contoh 1: onDestroy Activity dengan pembatalan coroutine lifecycleScope

Menunjukkan manajemen lifecycleScope yang benar di Activity: coroutine dijalankan untuk melacak status jaringan dan dibatalkan di onDestroy.

kotlin
class NetworkMonitorActivity : AppCompatActivity() {
    private val networkCallback = object : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network) {
            Log.d("NetworkMonitor", "Jaringan tersedia")
        }
        override fun onLost(network: Network) {
            Log.d("NetworkMonitor", "Jaringan hilang")
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_network)
        val connectivityManager = getSystemService(ConnectivityManager::class.java)
        connectivityManager.registerDefaultNetworkCallback(networkCallback)
        lifecycleScope.launch {
            Log.d("NetworkMonitor", "Pemantauan jaringan dimulai")
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        val connectivityManager = getSystemService(ConnectivityManager::class.java)
        connectivityManager.unregisterNetworkCallback(networkCallback)
        Log.d("NetworkMonitor", "onDestroy: callback dibatalkan")
    }
}

Di onDestroy, pendaftaran callback jaringan dibatalkan. lifecycleScope dibatalkan secara otomatis saat penghancuran siklus hidup — pembatalan terpisah coroutine tidak diperlukan. Callback jaringan harus berhenti berlangganan, jika tidak akan tetap ada di sistem bahkan setelah penghancuran Activity.

Contoh 2: onDestroy Fragment dengan pembersihan referensi View

Fragment membersihkan referensi ke View dengan benar di onDestroyView, mencegah kebocoran memori yang disebabkan oleh penutupan.

kotlin
class ProfileFragment : Fragment() {
    private var avatarView: ImageView? = null
    private var progressBar: ProgressBar? = null
    private val imageLoader = ImageLoader()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        avatarView = view.findViewById(R.id.avatar)
        progressBar = view.findViewById(R.id.progress)
        loadProfile()
    }

    private fun loadProfile() {
        viewLifecycleOwner.lifecycleScope.launch {
            try {
                progressBar?.visibility = View.VISIBLE
                val bitmap = imageLoader.load("https://example.com/avatar.png")
                avatarView?.setImageBitmap(bitmap)
            } finally {
                progressBar?.visibility = View.GONE
            }
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        avatarView = null
        progressBar = null
        imageLoader.cancel()
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d("ProfileFragment", "onDestroy: Fragment sepenuhnya dihancurkan")
    }
}

Di onDestroyView, referensi ke View diatur ke nol — ini mencegah kebocoran memori jika penutupan di imageLoader menahan referensi ke avatarView. Fragment itu sendiri dan ViewModel-nya tetap hidup hingga onDestroy. imageLoader.cancel() membatalkan pemuatan jika Fragment meninggalkan layar.

Contoh 3: Pemeriksaan isFinishing di onDestroy

Penggunaan isFinishing() memungkinkan membedakan apakah Activity berakhir atas perintah pengguna atau untuk pembuatan ulang.

kotlin
class AnalyticsActivity : AppCompatActivity() {
    private val analytics = Analytics()

    override fun onDestroy() {
        if (isFinishing) {
            Log.d("AnalyticsActivity", "Activity berakhir dengan finish() — mengirim analitik")
            analytics.sendSessionEnd()
        } else {
            Log.d("AnalyticsActivity", "Activity dibuat ulang (rotasi/konfigurasi) — tidak mengirim analitik")
        }
        super.onDestroy()
    }
}

Pemeriksaan isFinishing() — pola penting untuk analitik, pencatatan, dan pembersihan data sesi. Saat rotasi, tidak perlu mengirim peristiwa akhir sesi — pengguna masih bekerja dengan aplikasi. Menurut Google Analytics, pemeriksaan isFinishing() yang salah adalah penyebab 40% peristiwa sesi palsu.

Pertanyaan yang Sering Diajukan

Bisakah onDestroy tidak dipanggil?

Ya, bisa — saat pembunuhan proses oleh sistem (process death), Force Stop oleh pengguna atau penghentian darurat. Menurut data Google, sekitar 5–8% penghentian Activity terjadi tanpa panggilan onDestroy. Pengembang tidak boleh mengandalkan onDestroy untuk menyimpan data kritis — gunakan onPause atau onSaveInstanceState.

Apa perbedaan onDestroy dengan finish()?

finish() — panggilan yang memulai penghancuran Activity. onDestroy — callback yang dipanggil selama proses eksekusi finish(). finish() wajib untuk memanggil onDestroy pada penghentian normal. finish() dapat dipanggil oleh sistem atau pengembang, onDestroy — hanya callback sistem.

Apakah perlu memanggil super.onDestroy() di Fragment?

Ya, wajib baik di Activity maupun di Fragment. super.onDestroy() memastikan pembersihan yang benar dari ChildFragmentManager, LoaderManager dan komponen sistem lainnya. Melewatkan super.onDestroy() menyebabkan kebocoran memori dan bug dalam pemulihan fragment.

Kapan onCleared() di ViewModel dipanggil relatif terhadap onDestroy?

onCleared() dipanggil setelah onDestroy Activity atau Fragment, saat ViewModel tidak lagi diperlukan. Saat rotasi layar, onCleared() tidak dipanggil — ViewModel bertahan dari onDestroy. Urutan: onDestroy Activity/Fragment → (ViewModelStore dibersihkan) → onCleared().

Bisakah Service dimulai dari onDestroy?

Secara teknis ya, tetapi tidak disarankan. Activity segera dihancurkan setelah onDestroy dan Service yang dimulai tetap tanpa kontrol. Untuk tugas latar belakang, gunakan WorkManager dengan penundaan: WorkManager menjamin eksekusi bahkan setelah penghentian Activity dan bertahan dari process death.

Kesimpulan

  • onDestroy — callback akhir siklus hidup Activity dan Fragment, dipanggil sebelum penghancuran total komponen.
  • Panggilan onDestroy tidak dijamin saat process death — sekitar 5–8% penghentian terjadi tanpa itu.
  • Di onDestroy harus dibebaskan: callback jaringan, soket, aliran file, BroadcastReceiver, ContentObserver.
  • ViewModel.onCleared() dipanggil setelah onDestroy Activity — viewModelScope dibatalkan secara otomatis.
  • onDestroyView di Fragment (terpisah dari onDestroy) — tempat yang tepat untuk mengatur ulang referensi ke View.
  • Pemeriksaan isFinishing() di onDestroy memungkinkan membedakan penghentian finish() dari pembuatan ulang saat perubahan konfigurasi.
  • Jangan andalkan onDestroy untuk menyimpan data — gunakan onPause atau onSaveInstanceState.

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.

Diskusikan proyek

Baca juga