はじめに
Android 開発の中でも、Fragment のライフサイクルは “Activity より難しい” と感じるポイントのひとつ。
でも、仕組みを理解してしまえば Navigation / ViewPager2 / Clean Architecture どれを使っても怖くない存在になります。
本記事では、実務に直結する形で Fragment ライフサイクルをわかりやすく整理します。
Fragment は「UI を載せ替える部品」
Fragment は誤解されがちですが、
「画面そのもの」ではなく「Activity 内で動作する UI 単位の部品」 です。
✔ Activity に attach / detach される
✔ UI(View) は複数回作られ、何度でも破棄される
✔ でも Fragment オブジェクト自体は生き残り続ける
これが Fragment のライフサイクルを複雑に見せる元凶でもあります。
Fragment ライフサイクル(全ステップ一覧)
1. onAttach(Context)
最初に呼ばれるメソッド。
Fragment が Activity に “くっついた” タイミング。
- Context が利用可能に
- Hilt ならここで依存注入が入る
2. onCreate()
ここでは UI はまだ存在しない。
非UIロジックを準備する場所。
- ViewModel の初期化
- Fragment の状態変数の準備
3. onCreateView()
UI を作るフェーズ。
ここで XML を inflate したり、ViewBinding を生成する。
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return _binding!!.root
4. onViewCreated()
UI が完全に出来上がった瞬間。
実務ではここが “本番ステージ”。
- RecyclerView の adapter 設定
- ボタンのクリックリスナー
- LiveData / StateFlow の observe
- Animation の開始
UI のロジックは基本ここに書くのがベスト。
5. onStart()
画面が「ユーザーに見えるようになる」タイミング。
6. onResume()
ユーザーが操作可能になる状態。
Fragment が完全に前面に出た瞬間。
7. onPause()
フォーカスを失い始める。
8. onStop()
画面から完全に見えなくなる。
9. onDestroyView() ← 超重要
ここで ViewBinding を null にしてメモリリークを防ぐ。
Fragment は「UI を作り直す」のが常に起こるため、
View が存在しないのに binding が残るとリークの原因に。
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
10. onDestroy()
Fragment 自体の後始末。
- コルーチンの cancel
- リソース解放
11. onDetach()
Activity から完全に切り離される最後の瞬間。
Fragment ライフサイクル 図解
onAttach
↓
onCreate
↓
onCreateView
↓
onViewCreated
↓
onStart
↓
onResume
↑ ← UIが最も活発
------------------------------------
↓
onPause
↓
onStop
↓
onDestroyView ← View破棄(binding=null)
↓
onDestroy
↓
onDetach
実務で特に重要な 3 点だけ覚えて!
① UI ロジックは全部 onViewCreated に書く
createView では UI はまだ“不完全”。
② ViewBinding は onDestroyView で必ず破棄
View は必ず再生成される
→ binding = null しないとリークの嵐。
③ Fragment 本体は意外としぶとい
ViewPager2 / Navigation では、
“画面は消えても Fragment は生存” がしょっちゅう。
ViewModel も survive し続けるため、
「View がない時間の ViewModel イベント」は慎重に扱う必要あり。
ベストプラクティス(ViewBinding 版)
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.recyclerView.adapter = adapter
binding.button.setOnClickListener { /* ... */ }
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
まとめ
Fragment ライフサイクルは複雑に見えるけど、
【View のライフサイクル】と【Fragment 本体のライフサイクル】が別、
この一言に尽きます。
Fragment は生きてても、UI(View) はいくらでも死んでは生まれ変わる。
だから onDestroyView が一番大事。
これを理解すると、
Navigation Component, ViewPager2, StateFlow, DataBinding すべて扱いやすくなるよ。