π‘ Android Fragment Lifecycle Guide
π Mastering the Android Fragment Lifecycle: Modern Tips & Kotlin Code Examples
Fragments are essential for building modular and reusable UI components in Android. But with this power comes complexity β especially when managing the Fragment Lifecycle, which has some key differences from the Activity lifecycle.
In this guide, weβll explore each stage of the Fragment lifecycle, provide Kotlin code examples, and share modern development tips so you can avoid common pitfalls and write cleaner, more robust code.
π§© Fragment Lifecycle Overview
A Fragment
has two primary lifecycles:
- Fragment lifecycle: Deals with the fragment instance itself.
- View lifecycle: Deals with the UI (
View
) of the fragment.
These lifecycles donβt always move together β and thatβs why developers often hit bugs with view bindings and lifecycle observers.
π Fragment Lifecycle Flow (Visual)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
onAttach()
β
onCreate()
β
onCreateView()
β
onViewCreated()
β
onStart()
β
onResume()
β
-- Fragment Running --
β
onPause()
β
onStop()
β
onDestroyView()
β
onDestroy()
β
onDetach()
π§ Lifecycle Callbacks (with Kotlin Examples)
1οΈβ£ onAttach(context: Context)
1
2
3
4
override fun onAttach(context: Context) {
super.onAttach(context)
Log.d("Lifecycle", "onAttach")
}
β Use this for getting context references, initializing callbacks or listeners tied to the host activity.
2οΈβ£ onCreate(savedInstanceState: Bundle?)
1
2
3
4
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("Lifecycle", "onCreate")
}
β Use this for initializing ViewModels, arguments, or non-UI data.
3οΈβ£ onCreateView(...)
1
2
3
4
5
6
7
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.fragment_sample, container, false)
}
β Avoid accessing views here. Just inflate and return the view.
4οΈβ£ onViewCreated(view: View, savedInstanceState: Bundle?)
1
2
3
4
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Log.d("Lifecycle", "onViewCreated")
}
β Use this for binding views, setting up adapters, and observing LiveData.
5οΈβ£ onStart()
and onResume()
1
2
3
4
5
6
7
8
9
override fun onStart() {
super.onStart()
Log.d("Lifecycle", "onStart")
}
override fun onResume() {
super.onResume()
Log.d("Lifecycle", "onResume")
}
β Use for analytics, media, sensors, or UI updates.
6οΈβ£ onPause()
and onStop()
1
2
3
4
5
6
7
8
9
override fun onPause() {
super.onPause()
Log.d("Lifecycle", "onPause")
}
override fun onStop() {
super.onStop()
Log.d("Lifecycle", "onStop")
}
β Use for pausing media and saving state.
7οΈβ£ onDestroyView()
1
2
3
4
override fun onDestroyView() {
super.onDestroyView()
Log.d("Lifecycle", "onDestroyView")
}
β Nullify view binding and release UI resources here.
8οΈβ£ onDestroy()
and onDetach()
1
2
3
4
5
6
7
8
9
override fun onDestroy() {
super.onDestroy()
Log.d("Lifecycle", "onDestroy")
}
override fun onDetach() {
super.onDetach()
Log.d("Lifecycle", "onDetach")
}
β Clean up tasks and references to avoid memory leaks.
π¦ Full Fragment Lifecycle Example (Kotlin)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class SampleFragment : Fragment(R.layout.fragment_sample) {
override fun onAttach(context: Context) {
super.onAttach(context)
Log.d("Lifecycle", "onAttach")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("Lifecycle", "onCreate")
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Log.d("Lifecycle", "onViewCreated")
}
override fun onStart() {
super.onStart()
Log.d("Lifecycle", "onStart")
}
override fun onResume() {
super.onResume()
Log.d("Lifecycle", "onResume")
}
override fun onPause() {
super.onPause()
Log.d("Lifecycle", "onPause")
}
override fun onStop() {
super.onStop()
Log.d("Lifecycle", "onStop")
}
override fun onDestroyView() {
super.onDestroyView()
Log.d("Lifecycle", "onDestroyView")
}
override fun onDestroy() {
super.onDestroy()
Log.d("Lifecycle", "onDestroy")
}
override fun onDetach() {
super.onDetach()
Log.d("Lifecycle", "onDetach")
}
}
π§ββοΈ Tips & Tricks for Modern Fragment Development
β 1. Safe ViewBinding
1
2
3
4
5
6
7
8
9
10
11
private var _binding: FragmentSampleBinding? = null
private val binding get() = _binding!!
override fun onCreateView(...) = FragmentSampleBinding.inflate(inflater, container, false).also {
_binding = it
}.root
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
β 2. Share Data with ViewModel
1
private val sharedViewModel: SharedViewModel by activityViewModels()
β 3. Use Lifecycle-Aware Observers
1
2
3
4
5
6
7
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.stateFlow.collect {
// UI updates
}
}
}
β 4. Donβt Store Fragments in Static Fields
Instead, use:
1
2
3
supportFragmentManager.beginTransaction()
.replace(R.id.container, MyFragment())
.commit()
π§ Conclusion
Master the Fragment lifecycle to create high-performance, maintainable, and bug-free apps. Separate UI and business logic, use ViewModel, and always clean up bindings to avoid leaks.