onDestroy — AndroidにおけるActivityとFragmentのライフサイクルの最終メソッドで、コンポーネントが完全に破棄される前に呼び出されます。onDestroyはActivityまたはFragmentがその作業を終了していることを示します:すべてのリソースを解放し、ネストされたフラグメントを破棄し、ViewModelをクリアする必要があります。Googleによると、onDestroyはActivity終了の100%のケースで呼び出されますが、プロセス死亡(process death)時にはシステムがonDestroy呼び出しを完全にスキップする可能性があります。 onDestroyに関するAndroidドキュメントは、このメソッドが異常終了時に呼び出しを保証しないことを強調しています。
重要なポイント
onDestroy — AndroidがActivityまたはFragmentを完全に破棄する前に呼び出すコールバックメソッドです。これは開発者がリソースを解放し、バックグラウンド操作をキャンセルし、データ処理を終了する最後の機会です。onDestroyの実行後、Activity/Fragmentインスタンスはガベージコレクション(GC)の対象としてマークされ、使用できなくなります。
onDestroyが呼び出される理由:
Google Android Vitalsの統計(2025年)によると、すべてのActivity破棄ケースの約12%が画面回転によるもの、65%がfinish()によるもの、23%が設定変更によるものです。onDestroyがスキップされるプロセス死亡の割合は、RAMが少ないデバイス(4GB未満)に依存して約5–8%です。
onDestroyはほとんどの標準的なシナリオで呼び出されますが、開発者が考慮すべき重要な例外があります。onDestroy呼び出しの保証を理解することは、アプリケーションアーキテクチャにとって重要であり、特にデータ保存とWorkManagerタスクのキャンセルに関して重要です。
onDestroyが呼び出されるタイミング:
onDestroyが呼び出されないタイミング:
onDestroy呼び出しの保証がないため、Googleは以下を推奨しています:重要なデータを保存するためにonDestroyに決して依存しないでください。onSaveInstanceState()、WorkManager、または自動保存機能付きのRoomを使用してください。onDestroyはリソース解放のためのものであり、永続化のためのものではありません。
onDestroyはActivityとFragmentの両方に存在しますが、契約が異なります。Fragmentのライフサイクルはより詳細で、onDestroyの他にonDestroyView(View階層の破棄)とonDetach(Activityからの切り離し)があります。
| コンポーネント | 破棄メソッド | 順序 | ViewModelの生存 |
|---|---|---|---|
| Activity | onDestroy | onPause → onStop → onDestroy | いいえ(ViewModelStoreが保存されない場合) |
| Fragment | onDestroyView, onDestroy, onDetach | onPause → onStop → onDestroyView → onDestroy → onDetach | はい(Fragmentが削除されない場合) |
主な違い:FragmentのViewはFragment自体よりも頻繁に再作成されます。画面回転時に、FragmentはonDestroyView(View破棄)を経由しますが、Fragment自体とそのViewModelは生き続けます。onDestroyViewは、メモリリークを防ぐためにView参照をクリーンアップする適切な場所です。FragmentのonDestroyはActivityのonDestroyと類似しており、Fragmentが完全に削除されたときに呼び出されます。
子フラグメントは親FragmentのonDestroyの前に破棄されます。Activity内では、子フラグメントは親ActivityのonDestroyが呼び出されたときにonDestroyを受け取ります。順序は保証されています:フラグメントはそれを含むActivityより先に終了します。
onDestroyは、ActivityまたはFragmentよりも長く生き続けるべきではないすべてのリソースを解放するためのものです。復帰までリソースを解放するonStopとは異なり、onDestroyは最終的なクリーンアップを実行します。
onDestroyでの必須アクションのチェックリスト:
onDestroyで行うべきでないこと: onDestroyでデータを保存しないでください — onPauseまたはonSaveInstanceStateを使用してください。新しいServiceやWorkManagerタスクを開始しないでください — Activityは破棄され、結果を追跡できなくなります。UIの更新を試みないでください — View階層はすでに破棄されているか、破棄の過程にあります。findViewById()を呼び出すとnullが返ります。
ViewModelは、画面回転時にActivityのonDestroyを生き残るように設計されていますが、finish()時にはActivityとともに破棄されます。この非対称な動作が、開発者の間で混乱の主な原因となっています。
画面回転時:
finish()時(ユーザーが“戻る”を押した場合):
したがって、onDestroyでviewModelScopeをキャンセルする必要はありません — ViewModelが自動的に行います。lifecycleScope(ViewModelではなくActivityにバインドされている)を使用している場合は、onDestroy内でlifecycleScope.cancel()を介してキャンセルするか、Jobを手動で管理してください。
Activityでの正しいlifecycleScope管理を示します:ネットワークステータスを監視するためにコルーチンが起動され、onDestroyでキャンセルされます。
class NetworkMonitorActivity : AppCompatActivity() {
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
Log.d("NetworkMonitor", "ネットワーク利用可能")
}
override fun onLost(network: Network) {
Log.d("NetworkMonitor", "ネットワーク喪失")
}
}
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", "ネットワーク監視開始")
}
}
override fun onDestroy() {
super.onDestroy()
val connectivityManager = getSystemService(ConnectivityManager::class.java)
connectivityManager.unregisterNetworkCallback(networkCallback)
Log.d("NetworkMonitor", "onDestroy: コールバックがキャンセルされました")
}
}
onDestroyでは、ネットワークコールバックの登録がキャンセルされます。lifecycleScopeはライフサイクルが破棄されると自動的にキャンセルされます — 個別のコルーチンキャンセルは必要ありません。ネットワークコールバックは必ず登録解除する必要があります。そうしないと、Activityが破棄された後もシステムに残り続けます。
FragmentはonDestroyViewでView参照を適切にクリアし、クロージャによるメモリリークを防ぎます。
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が完全に破棄されました")
}
}
onDestroyViewでは、View参照がnullに設定されます — これにより、imageLoader内のクロージャがavatarViewへの参照を保持している場合のメモリリークを防ぎます。Fragment自体とそのViewModelはonDestroyまで生き続けます。imageLoader.cancel()は、Fragmentが画面から離れた場合にロードをキャンセルします。
isFinishing()を使用すると、Activityがユーザーコマンドで終了しているのか、再作成のために終了しているのかを区別できます。
class AnalyticsActivity : AppCompatActivity() {
private val analytics = Analytics()
override fun onDestroy() {
if (isFinishing) {
Log.d("AnalyticsActivity", "finish()でActivity終了 — アナリティクスを送信")
analytics.sendSessionEnd()
} else {
Log.d("AnalyticsActivity", "Activity再作成中(回転/設定変更)— アナリティクスを送信しません")
}
super.onDestroy()
}
}
isFinishing()の確認は、アナリティクス、ロギング、セッションデータのクリーンアップにとって重要なパターンです。回転時には、セッション終了イベントを送信すべきではありません — ユーザーはまだアプリケーションで作業しています。Google Analyticsによると、不適切なisFinishing()の確認は、40%の誤ったセッションイベントの原因となっています。
よくある質問
はい、あります — システムによるプロセス死亡、ユーザーによる強制停止、または異常終了時です。Googleによると、約5–8%のActivity終了がonDestroy呼び出しなしで発生します。開発者は重要なデータを保存するためにonDestroyに依存すべきではありません — onPauseまたはonSaveInstanceStateを使用してください。
finish() — Activityの破棄を開始する呼び出しです。onDestroy — finish()の実行中に呼び出されるコールバックです。通常の終了時にonDestroyが呼び出されるためにはfinish()が必要です。finish()はシステムまたは開発者によって呼び出される可能性がありますが、onDestroyはシステムコールバックのみです。
はい、必須です ActivityとFragmentの両方で。super.onDestroy()は、ChildFragmentManager、LoaderManager、その他のシステムコンポーネントの適切なクリーンアップを保証します。super.onDestroy()をスキップすると、メモリリークやフラグメント復元のバグが発生します。
onCleared()はActivityまたはFragmentのonDestroyの後に呼び出されます。ViewModelが必要なくなった時点です。画面回転時には、onCleared()は呼び出されません — ViewModelはonDestroyを生き残ります。順序:Activity/FragmentのonDestroy →(ViewModelStoreがクリアされる)→ onCleared()。
技術的には可能ですが、推奨されません。ActivityはonDestroyの直後に破棄され、開始されたServiceは制御不能になります。バックグラウンドタスクには、遅延付きのWorkManagerを使用してください。WorkManagerはActivity終了後も実行を保証し、プロセス死亡を生き残ります。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。