Table of Contents
Understanding the Fragment Lifecycle
Fragments have their own lifecycle that is related to, but not identical with, the activity lifecycle. Understanding how fragments move between states is essential for writing stable and efficient Android apps that use dynamic UIs and multiple screens within a single activity.
In this chapter you will focus on the unique lifecycle of fragments, how it interacts with the host activity, and what kind of work is appropriate in each lifecycle method.
Fragment Lifecycle vs Activity Lifecycle
An activity manages the overall window of your app. A fragment lives inside that activity and provides a portion of the UI or behavior that can be reused or combined with other fragments.
A fragment lifecycle has more states than an activity because it deals not only with its existence as an object, but also with the creation and destruction of its view hierarchy. This means a fragment can be kept in memory while its view is destroyed and later recreated.
Fragments are managed by a FragmentManager. When you add, remove, show, or hide a fragment, the FragmentManager drives the lifecycle transitions, and Android calls the corresponding lifecycle callbacks on your fragment.
Core Fragment Lifecycle Methods
A typical fragment lifecycle from creation to destruction goes through several main callback methods. In practice you might not override all of them, but you should understand what each one is meant for.
The most important callbacks are:
onAttach()
onCreate()
onCreateView()
onViewCreated()
onStart()
onResume()
onPause()
onStop()
onDestroyView()
onDestroy()
onDetach()
The lifecycle begins with onAttach() and ends with onDetach(). Between these callbacks the fragment may create, destroy, and recreate its view multiple times.
Later Android versions also introduce lifecycle events for visible hints, such as onHiddenChanged(), but the foundation always remains the core callbacks above.
From Attach to Creation
The first time a fragment is associated with an activity, Android calls onAttach(). At this point the fragment is connected to its host, but it does not yet have a view or saved state restored.
Inside onAttach(), the fragment receives a Context which is usually the host activity. This is the place where you can perform initial interactions that require access to the activity as a context, such as storing a reference to a callback interface implemented by the activity.
After attachment, Android calls onCreate(). This is where you perform non UI related initial setup that should occur once for the fragment instance. You can initialize variables, start loading data that does not require the view, or restore state from savedInstanceState.
A typical fragment beginning looks like this:
class ExampleFragment : Fragment() {
override fun onAttach(context: Context) {
super.onAttach(context)
// Get references that need a Context or Activity
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Initialize logic, read arguments, restore non-UI state
}
}At this stage the fragment exists, but nothing is visible yet because its view has not been created.
Creating and Initializing the Fragment View
The creation of the fragment user interface is split into two main callbacks.
onCreateView() is responsible for creating and returning the fragment view hierarchy. Typically you inflate a layout XML here using LayoutInflater. This method returns the root View that becomes the fragment UI.
onViewCreated() is called immediately after onCreateView() with the root view as a parameter. This is a convenient place to perform final initialization of your UI, such as setting up adapters, listeners, or binding view models to views.
A common pattern is:
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_example, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Access views using view.findViewById(...)
// Set up click listeners, adapters, and observers
}
You should avoid performing heavy operations directly in onCreateView() because this method runs every time the view is created, including after configuration changes or when the fragment comes back from the back stack and the view is recreated.
Visibility: Start and Resume
After the view is created, the fragment enters the visible part of the lifecycle.
onStart() is called when the fragment is becoming visible to the user. At this point the fragment is visible but may not yet be in the foreground or interacting with the user. You can start UI related work that should run while the fragment is visible, such as registering broadcast receivers that update the UI or starting animations.
onResume() follows when the fragment is fully visible and the user can interact with it. The fragment is in the foreground of the activity. This is a good point for starting tasks that must run only while the fragment is actively in use, such as starting a camera preview, listening for text input changes that update live results, or resuming a running game loop.
Conceptually, after onResume() the fragment is in its most active state. Any UI interaction or real time logic usually assumes that the fragment is resumed.
Pausing and Stopping the Fragment
When the fragment is no longer in the foreground or is being covered by another UI element, the lifecycle moves in the opposite direction.
onPause() is called first when the fragment is no longer in the foreground. The fragment might still be visible behind another window, such as a dialog. This method is where you pause ongoing actions that should not continue while the user is not actively using the fragment. Examples include pausing video playback or committing unsaved text input to a temporary variable.
onStop() is called after onPause() when the fragment is no longer visible at all. At this point the fragment can release resources that relate to visibility but not to the core existence of the fragment, like stopping animations that are off screen, disconnecting from UI related services, or unregistering UI updates.
The sequence around visibility is:
onStart()
onResume()
onPause()
onStop()
During these transitions, the fragment view still exists unless onDestroyView() is called. That means you can still refer to view objects in onPause() and onStop() as long as the view has not yet been destroyed.
Destroying and Recreating the Fragment View
Unlike an activity, a fragment can have its view destroyed while the fragment instance itself remains created. This is an important distinction and a common source of bugs.
onDestroyView() is called when the view hierarchy associated with the fragment is being removed. This may happen when the fragment is replaced, removed, or when the fragment is put on the back stack and later needs to free its views to save memory. After this point, any reference to views must be cleared to avoid memory leaks.
If you are using view binding, this is the place where you should set the binding reference to null. If you keep references to views as properties, they must be cleared in onDestroyView().
After the view is destroyed, the fragment may still remain attached to the activity and continue to hold non UI state in memory. Later the system can call onCreateView() and onViewCreated() again to recreate the view when needed, for example if the user navigates back to this fragment.
If the fragment itself is being destroyed, onDestroy() will be called after onDestroyView(). Use onDestroy() for cleaning up any remaining state that should be cleared when the fragment instance is removed, such as canceling coroutines that are tied to the fragment instance or closing non UI resources that were opened in onCreate().
Finally, onDetach() is called when the fragment is no longer associated with its activity. After this callback, the fragment does not have access to the activity context anymore.
Lifecycle and Back Stack Behavior
When a fragment transaction is added to the back stack, the fragment lifecycle behaves differently than when it is simply removed.
If you replace a fragment and add the transaction to the back stack, the fragment is stopped and its view is destroyed, but the fragment instance remains. The lifecycle path for the outgoing fragment is usually:
onPause()
onStop()
onDestroyView()
The fragment then stays in memory. When the user presses the back button and navigates back, the fragment does not go through onCreate() again. Instead, Android recreates the view:
onCreateView()
onViewCreated()
onStart()
onResume()
If you remove a fragment without adding the transaction to the back stack, the fragment is fully destroyed and detached, so it follows the complete path including onDestroy() and onDetach().
This distinction affects how you manage state. Data that should survive view recreation but not fragment destruction can be kept in properties that are reset in onDestroy(). Data that should survive process death or full recreation is better stored using arguments, a ViewModel, or saved state mechanisms that are not specific to this chapter.
Handling Configuration Changes with Fragments
Configuration changes, such as rotating the device or changing the system language, cause the host activity to be destroyed and recreated. Fragments that belong to that activity usually follow along.
In a typical scenario, when a configuration change occurs, the activity and its fragments will go through the full destruction and recreation sequence. This means:
onPause()
onStop()
onDestroyView()
onDestroy()
onDetach()
Then new instances of the activity and fragments are created, and the fragment lifecycle starts again from onAttach().
There are ways to preserve fragment instances across configuration changes, but they require explicit configuration and can lead to complexity. For most beginner level use cases, you should allow the system to recreate fragments and rely on proper state handling rather than forcing fragments to survive configuration changes.
Practical Usage Patterns in Fragment Lifecycle
To work effectively with fragments, it is helpful to associate typical tasks with specific lifecycle methods. The goal is to avoid memory leaks, crashes caused by invalid view references, and unnecessary heavy work.
Initialization that does not depend on the view, such as reading arguments from arguments or setting up non UI data, belongs in onCreate().
View inflation belongs in onCreateView(). You should not start long running operations here because the method can be called multiple times and should be relatively fast.
View related initialization such as findViewById, setting click listeners, or binding LiveData observers to views belongs in onViewCreated().
Starting operations that must run while the fragment is visible, but not necessarily in the foreground, usually belongs in onStart(). Tasks that need user interaction or should run only when the fragment is fully active often go into onResume().
Pausing or releasing resources that are only needed when the fragment is visible should be done in onPause() and onStop().
Resetting view references and cleaning up bindings must happen in onDestroyView() to avoid holding on to old view objects.
Cleaning up any remaining resources and canceling longer lived tasks that should not outlive the fragment instance belongs in onDestroy().
Finally, clearing references to the activity or context based callback interfaces should happen in onDetach().
Always clear references to views in onDestroyView() to prevent memory leaks, and never use a view reference after this method has been called.
Summary of the Fragment Lifecycle Flow
Putting it all together, a full typical lifecycle of a fragment during its existence follows this order:
onAttach()
onCreate()
onCreateView()
onViewCreated()
onStart()
onResume()
onPause()
onStop()
onDestroyView()
onDestroy()
onDetach()
In real apps, the fragment may move back and forth among a subset of these callbacks, especially when it is put on the back stack and its view is destroyed and recreated. Your main task as an Android developer is to place the right logic in the right lifecycle methods so that fragments behave correctly whenever the system decides to change their state.