onDestroyとは — AndroidにおけるActivityの終了処理

著者: IT Sectr 公開日: 2026-03-04 読了時間: 8 分

onDestroy — AndroidにおけるActivityとFragmentのライフサイクルの最終メソッドで、コンポーネントが完全に破棄される前に呼び出されます。onDestroyはActivityまたはFragmentがその作業を終了していることを示します:すべてのリソースを解放し、ネストされたフラグメントを破棄し、ViewModelをクリアする必要があります。Googleによると、onDestroyはActivity終了の100%のケースで呼び出されますが、プロセス死亡(process death)時にはシステムがonDestroy呼び出しを完全にスキップする可能性があります。 onDestroyに関するAndroidドキュメントは、このメソッドが異常終了時に呼び出しを保証しないことを強調しています。

重要なポイント

  • onDestroy — ActivityまたはFragmentを破棄する前の最後の呼び出しで、最終的なリソースクリーンアップを目的としています。
  • システムによるプロセス死亡時にはonDestroy呼び出しは保証されません — 重要なデータを保存するためにこれに依存しないでください。
  • onDestroyでは、バックグラウンドタスクのキャンセル、ソケットとデータベースのクローズ、ViewModelStoreのクリアが必要です。
  • onStopとの違い:onStop — 可視性の喪失(Activityはメモリに残る)、onDestroy — 完全な破棄。
  • onDestroy内のisFinishing()は、Activityがユーザーコマンド(finish())またはシステムの決定によって終了しているかを示します。

onDestroy:Androidにおける概要

onDestroy — AndroidがActivityまたはFragmentを完全に破棄する前に呼び出すコールバックメソッドです。これは開発者がリソースを解放し、バックグラウンド操作をキャンセルし、データ処理を終了する最後の機会です。onDestroyの実行後、Activity/Fragmentインスタンスはガベージコレクション(GC)の対象としてマークされ、使用できなくなります。

onDestroyが呼び出される理由:

  • 明示的なfinish()呼び出し — ユーザーが“戻る”を押した、または開発者がfinishActivity()を呼び出した。
  • 画面回転 — Activityが破棄され、新しい設定で再作成される。
  • 設定変更 — キーボード、言語変更、画面サイズ変更(マルチウィンドウ)。
  • システムの判断 — Androidがリソース解放のためにActivityを強制終了する(ただしonDestroyが呼び出されない場合がある)。

Google Android Vitalsの統計(2025年)によると、すべてのActivity破棄ケースの約12%が画面回転によるもの、65%がfinish()によるもの、23%が設定変更によるものです。onDestroyがスキップされるプロセス死亡の割合は、RAMが少ないデバイス(4GB未満)に依存して約5–8%です。

onDestroyが呼び出されるタイミングと呼び出されないタイミング

onDestroyはほとんどの標準的なシナリオで呼び出されますが、開発者が考慮すべき重要な例外があります。onDestroy呼び出しの保証を理解することは、アプリケーションアーキテクチャにとって重要であり、特にデータ保存とWorkManagerタスクのキャンセルに関して重要です。

onDestroyが呼び出されるタイミング:

  • ユーザーが“戻る”ボタンを押す — Activity.finish() → onPause → onStop → onDestroy。
  • 画面回転 — Activityが破棄され(onPause → onStop → onDestroy)、その後再作成される。
  • 設定変更 — Activityの再作成を必要とするシステム設定。
  • finishAffinity()の呼び出し — スタック内のすべてのActivityを終了。
  • FragmentManagerからのFragment削除 — Fragmentが受信:onPause → onStop → onDestroyView → onDestroy → onDetach。

onDestroyが呼び出されないタイミング:

  • システムによるプロセス死亡 — メモリ不足時にAndroidがアプリケーションプロセス全体を強制終了する。プロセスがLinuxカーネルレベルで終了するため、ActivityはonDestroyを受け取りません。
  • 異常終了 — メインスレッドでキャッチされない例外がonDestroyを呼び出さずにアプリケーションを強制終了する。
  • 強制停止 — ユーザーが設定でアプリケーションを強制的に停止する。

onDestroy呼び出しの保証がないため、Googleは以下を推奨しています:重要なデータを保存するためにonDestroyに決して依存しないでください。onSaveInstanceState()、WorkManager、または自動保存機能付きのRoomを使用してください。onDestroyはリソース解放のためのものであり、永続化のためのものではありません。

ActivityとFragmentにおけるonDestroy:共通点と相違点

onDestroyはActivityとFragmentの両方に存在しますが、契約が異なります。Fragmentのライフサイクルはより詳細で、onDestroyの他にonDestroyView(View階層の破棄)とonDetach(Activityからの切り離し)があります。

コンポーネント破棄メソッド順序ViewModelの生存
ActivityonDestroyonPause → onStop → onDestroyいいえ(ViewModelStoreが保存されない場合)
FragmentonDestroyView, onDestroy, onDetachonPause → 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で行うべきこと:クリーンアップチェックリスト

onDestroyは、ActivityまたはFragmentよりも長く生き続けるべきではないすべてのリソースを解放するためのものです。復帰までリソースを解放するonStopとは異なり、onDestroyは最終的なクリーンアップを実行します。

onDestroyでの必須アクションのチェックリスト:

  • コルーチンとFlowのキャンセル — viewModelScopeにバインドされていないジョブをキャンセルします。viewModelScopeは自動的にキャンセルされますが、lifecycleScopeはActivityのライフサイクルにバインドされています。
  • ソケットとチャネルのクローズ — WebSocket(OkHttp)、BluetoothSocket、ServerSocket。破棄後に開いたままにしておくと、システムリソースリークになります。
  • ファイルとストリームのクローズ — FileInputStream、FileOutputStream、Cursor。Cursorは閉じられない場合、ContentProviderでANRを引き起こす可能性があります。
  • ContentObserverの登録解除 — Activityがコンテンツ変更(連絡先、メディアライブラリ)を監視している場合。
  • BroadcastReceiverの登録解除 — 動的に登録されたレシーバーはキャンセルする必要があります。
  • データベースのクローズ — RoomはApplication破棄時に自動的に接続を閉じますが、直接のSQLiteDatabaseは手動のclose()が必要です。

onDestroyで行うべきでないこと: onDestroyでデータを保存しないでください — onPauseまたはonSaveInstanceStateを使用してください。新しいServiceやWorkManagerタスクを開始しないでください — Activityは破棄され、結果を追跡できなくなります。UIの更新を試みないでください — View階層はすでに破棄されているか、破棄の過程にあります。findViewById()を呼び出すとnullが返ります。

onDestroyとViewModel:連携

ViewModelは、画面回転時にActivityのonDestroyを生き残るように設計されていますが、finish()時にはActivityとともに破棄されます。この非対称な動作が、開発者の間で混乱の主な原因となっています。

画面回転時:

  • Activity:onPause → onStop → onDestroy(Activity破棄)。
  • ViewModel:破棄されない — ViewModelStoreが保存され、新しいActivityに渡されます。
  • 新しいActivity:onCreate → onStart → onResume、同じViewModelを受け取ります。

finish()時(ユーザーが“戻る”を押した場合):

  • Activity:onPause → onStop → onDestroy。
  • ViewModel:onCleared() — ActivityのonDestroyの後に呼び出されます。
  • すべてのviewModelScopeコルーチンが自動的にキャンセルされます。

したがって、onDestroyでviewModelScopeをキャンセルする必要はありません — ViewModelが自動的に行います。lifecycleScope(ViewModelではなくActivityにバインドされている)を使用している場合は、onDestroy内でlifecycleScope.cancel()を介してキャンセルするか、Jobを手動で管理してください。

KotlinでのonDestroyを使用したコード例

例1:lifecycleScopeコルーチンキャンセルを伴うonDestroy Activity

Activityでの正しいlifecycleScope管理を示します:ネットワークステータスを監視するためにコルーチンが起動され、onDestroyでキャンセルされます。

kotlin
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が破棄された後もシステムに残り続けます。

例2:View参照クリーンアップを伴うonDestroy Fragment

FragmentはonDestroyViewでView参照を適切にクリアし、クロージャによるメモリリークを防ぎます。

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が完全に破棄されました")
    }
}

onDestroyViewでは、View参照がnullに設定されます — これにより、imageLoader内のクロージャがavatarViewへの参照を保持している場合のメモリリークを防ぎます。Fragment自体とそのViewModelはonDestroyまで生き続けます。imageLoader.cancel()は、Fragmentが画面から離れた場合にロードをキャンセルします。

例3:onDestroyでのisFinishing確認

isFinishing()を使用すると、Activityがユーザーコマンドで終了しているのか、再作成のために終了しているのかを区別できます。

kotlin
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%の誤ったセッションイベントの原因となっています。

よくある質問

onDestroyが呼び出されないことはありますか?

はい、あります — システムによるプロセス死亡、ユーザーによる強制停止、または異常終了時です。Googleによると、約5–8%のActivity終了がonDestroy呼び出しなしで発生します。開発者は重要なデータを保存するためにonDestroyに依存すべきではありません — onPauseまたはonSaveInstanceStateを使用してください。

onDestroyとfinish()の違いは何ですか?

finish() — Activityの破棄を開始する呼び出しです。onDestroy — finish()の実行中に呼び出されるコールバックです。通常の終了時にonDestroyが呼び出されるためにはfinish()が必要です。finish()はシステムまたは開発者によって呼び出される可能性がありますが、onDestroyはシステムコールバックのみです。

Fragmentでsuper.onDestroy()を呼び出す必要がありますか?

はい、必須です ActivityとFragmentの両方で。super.onDestroy()は、ChildFragmentManager、LoaderManager、その他のシステムコンポーネントの適切なクリーンアップを保証します。super.onDestroy()をスキップすると、メモリリークやフラグメント復元のバグが発生します。

onDestroyに対してViewModelのonCleared()はいつ呼び出されますか?

onCleared()はActivityまたはFragmentのonDestroyの後に呼び出されます。ViewModelが必要なくなった時点です。画面回転時には、onCleared()は呼び出されません — ViewModelはonDestroyを生き残ります。順序:Activity/FragmentのonDestroy →(ViewModelStoreがクリアされる)→ onCleared()。

onDestroyからServiceを開始できますか?

技術的には可能ですが、推奨されません。ActivityはonDestroyの直後に破棄され、開始されたServiceは制御不能になります。バックグラウンドタスクには、遅延付きのWorkManagerを使用してください。WorkManagerはActivity終了後も実行を保証し、プロセス死亡を生き残ります。

まとめ

  • onDestroy — ActivityとFragmentの最終ライフサイクルコールバックで、コンポーネントの完全破棄前に呼び出されます。
  • onDestroy呼び出しはプロセス死亡時に保証されません — 約5–8%の終了がそれなしで発生します。
  • onDestroyで解放すべきもの:ネットワークコールバック、ソケット、ファイルストリーム、BroadcastReceiver、ContentObserver。
  • ViewModel.onCleared()はActivityのonDestroyの後に呼び出されます — viewModelScopeは自動的にキャンセルされます。
  • FragmentのonDestroyView(onDestroyとは別) — View参照をnullにする適切な場所です。
  • onDestroyでのisFinishing()確認により、finish()による終了と設定変更による再作成を区別できます。
  • データ保存のためにonDestroyに依存しないでください — onPauseまたはonSaveInstanceStateを使用してください。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください