How to use fragments

A fragment represents a modular portion of the user interface within an activity. A fragment has its own lifecycle, receives its own input events, and you can add or remove fragments while the containing activity is running.

This document describes how to create a fragment and include it in an activity.

Setup your environment

Fragments require a dependency on the AndroidX Fragment library.

To include the AndroidX Fragment library to your project, add the following dependencies in your app’s build.gradle file:

dependencies {
    val fragment_version = "1.8.8"

    // Java language implementation
    implementation("androidx.fragment:fragment:$fragment_version")
    // Kotlin
    implementation("androidx.fragment:fragment-ktx:$fragment_version")
}

Create a fragment class

To create a fragment, extend the AndroidX Fragment class, and override its methods to insert your app logic, similar to the way you would create an Activity class. To create a minimal fragment that defines its own layout, provide your fragment’s layout resource to the base constructor, as shown in the following example:

class ExampleFragment : Fragment(R.layout.example_fragment)

You can customize the fragment’s view by overriding the onCreateView() method.

class ExampleFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment.
        // or you can inflate a different layout here.
        val root: View = inflater.inflate(R.layout.my_fragment_layout, container, false)
        
        // Additional graphical initialisations...
        
        return root
    }
}

Difference and uses of onCreate(), onCreateView() in fragments

onCreate():

public void onCreate (Bundle savedInstanceState)

Called to do initial creation of a fragment. The onCreate() method in a Fragment is called after the Activity’s onAttachFragment() but before that Fragment’s onCreateView().
In this method, you can assign variables, get Intent extras, and anything else that doesn’t involve the View hierarchy (i.e. non-graphical initialisations). This is because this method can be called when the Activity’s onCreate() is not finished, and so trying to access the View hierarchy here may result in a crash.

onCreateView():

public View onCreateView (LayoutInflater inflater, 
                ViewGroup container, 
                Bundle savedInstanceState)

Called to have the fragment instantiate its user interface view. After the onCreate() is called (in the Fragment), the Fragment’s onCreateView() is called. You can assign your View variables and do any graphical initialisations. You are expected to return a View from this method, and this is the main UI view, but if your Fragment does not use any layouts or graphics, you can return null (happens by default if you don’t override).

To sum up

They are all called in the Fragment but are called at different times.
The onCreate() is called first, for doing any non-graphical initialisations. Next, you can assign and declare any View variables you want to use in onCreateView().

Add a fragment to an activity

Generally, your fragment must be embedded within an AndroidX FragmentActivity to contribute a portion of UI to that activity’s layout. FragmentActivity is the base class for AppCompatActivity, so if you’re already subclassing AppCompatActivity to provide backward compatibility in your app, then you do not need to change your activity base class.

You can add your fragment to the activity’s view hierarchy either by defining the fragment in your activity’s layout file or by defining a fragment container in your activity’s layout file and then programmatically adding the fragment from within your activity. In either case, you need to add a FragmentContainerView that defines the location where the fragment should be placed within the activity’s view hierarchy. It is strongly recommended to always use a FragmentContainerView as the container for fragments, as FragmentContainerView includes fixes specific to fragments that other view groups such as FrameLayout do not provide.

Add a fragment via XML

To declaratively add a fragment to your activity layout’s XML, use a FragmentContainerView element.

Here’s an example activity layout containing a single FragmentContainerView:

<!-- res/layout/example_activity.xml -->
<androidx.fragment.app.FragmentContainerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_container_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:name="com.example.ExampleFragment" />

The android:name attribute specifies the class name of the Fragment to instantiate. When the activity’s layout is inflated, the specified fragment is instantiated, onInflate() is called on the newly instantiated fragment, and a FragmentTransaction is created to add the fragment to the FragmentManager.

Note: You can use the class attribute instead of android:name as an alternative way to specify which Fragment to instantiate.

Add a fragment programmatically

To programmatically add a fragment to your activity’s layout, the layout should include a FragmentContainerView to serve as a fragment container, as shown in the following example:

<!-- res/layout/example_activity.xml -->
<androidx.fragment.app.FragmentContainerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_container_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Unlike the XML approach, the android:name attribute isn’t used on the FragmentContainerView here, so no specific fragment is automatically instantiated. Instead, a FragmentTransaction is used to instantiate a fragment and add it to the activity’s layout.

While your activity is running, you can make fragment transactions such as adding, removing, or replacing a fragment. In your FragmentActivity, you can get an instance of the FragmentManager, which can be used to create a FragmentTransaction. Then, you can instantiate your fragment within your activity’s onCreate() method using FragmentTransaction.add(), passing in the ViewGroup ID of the container in your layout and the fragment class you want to add and then commit the transaction, as shown in the following example:

class ExampleActivity : AppCompatActivity(R.layout.example_activity) {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (savedInstanceState == null) {
            supportFragmentManager.commit {
                setReorderingAllowed(true)
                add<ExampleFragment>(R.id.fragment_container_view)
            }
        }
    }
}

Note: You should always use setReorderingAllowed(true) when performing a FragmentTransaction. For more information on reordered transactions, see Fragment transactions.

In the previous example, note that the fragment transaction is only created when savedInstanceState is null. This is to ensure that the fragment is added only once, when the activity is first created. When a configuration change occurs and the activity is recreated, savedInstanceState is no longer null, and the fragment does not need to be added a second time, as the fragment is automatically restored from the savedInstanceState.

Fragment manager

Note: We strongly recommend using the Navigation library to manage your app’s navigation. The framework follows best practices for working with fragments, the back stack, and the fragment manager. For more information about Navigation, see Get started with the Navigation component and Migrate to the Navigation component.

FragmentManager is the class responsible for performing actions on your app’s fragments, such as adding, removing, or replacing them and adding them to the back stack.

You might never interact with FragmentManager directly if you’re using the Jetpack Navigation library, as it works with the FragmentManager on your behalf. However, any app using fragments is using FragmentManager at some level, so it’s important to understand what it is and how it works.

Access the FragmentManager

You can access the FragmentManager from an activity or from a fragment.

FragmentActivity and its subclasses, such as AppCompatActivity, have access to the FragmentManager through the getSupportFragmentManager() method.

Fragments can host one or more child fragments. Inside a fragment, you can get a reference to the FragmentManager that manages the fragment’s children through getChildFragmentManager(). If you need to access its host FragmentManager, you can use getParentFragmentManager().

Here are a couple of examples to see the relationships between fragments, their hosts, and the FragmentManager instances associated with each.

two ui layout examples showing the relationships between
            fragments and their host activities

Figure 1. Two UI layout examples showing the relationships between fragments and their host activities.

Figure 1 shows two examples, each of which has a single activity host. The host activity in both of these examples displays top-level navigation to the user as a BottomNavigationView that is responsible for swapping out the host fragment with different screens in the app. Each screen is implemented as a separate fragment.

The host fragment in Example 1 hosts two child fragments that make up a split-view screen. The host fragment in Example 2 hosts a single child fragment that makes up the display fragment of a swipe view.

Given this setup, you can think about each host as having a FragmentManager associated with it that manages its child fragments. This is illustrated in figure 2 along with property mappings between supportFragmentManager, parentFragmentManager, and childFragmentManager.

each host has its own FragmentManager associated with it
            that manages its child fragments

Figure 2. Each host has its own FragmentManager associated with it that manages its child fragments.

The appropriate FragmentManager property to reference depends on where the callsite is in the fragment hierarchy along with which fragment manager you are trying to access.

Once you have a reference to the FragmentManager, you can use it to manipulate the fragments being displayed to the user.

Child fragments

Generally speaking, your app consists of a single or small number of activities in your application project, with each activity representing a group of related screens. The activity might provide a point to place top-level navigation and a place to scope ViewModel objects and other view-state between fragments. A fragment represents an individual destination in your app.

If you want to show multiple fragments at once, such as in a split-view or a dashboard, you can use child fragments that are managed by your destination fragment and its child fragment manager.

Other use cases for child fragments are the following:

  • Screen slides, using a ViewPager2 in a parent fragment to manage a series of child fragment views.
  • Sub-navigation within a set of related screens.
  • Jetpack Navigation uses child fragments as individual destinations. An activity hosts a single parent NavHostFragment and fills its space with different child destination fragments as users navigate through your app.

Use the FragmentManager

The FragmentManager manages the fragment back stack. At runtime, the FragmentManager can perform back stack operations like adding or removing fragments in response to user interactions. Each set of changes is committed together as a single unit called a FragmentTransaction. For a more in-depth discussion about fragment transactions, see the fragment transactions guide.

When the user taps the Back button on their device, or when you call FragmentManager.popBackStack(), the top-most fragment transaction pops off of the stack. If there are no more fragment transactions on the stack, and if you aren’t using child fragments, the Back event bubbles up to the activity. If you are using child fragments, see special considerations for child and sibling fragments.

When you call addToBackStack() on a transaction, the transaction can include any number of operations, such as adding multiple fragments or replacing fragments in multiple containers.

When the back stack is popped, all these operations reverse as a single atomic action. However, if you committed additional transactions prior to the popBackStack() call, and if you didn’t use addToBackStack() for the transaction, these operations don’t reverse. Therefore, within a single FragmentTransaction, avoid interleaving transactions that affect the back stack with those that don’t.

Perform a transaction

To display a fragment within a layout container, use the FragmentManager to create a FragmentTransaction. Within the transaction, you can then perform an add() or replace() operation on the container.

For example, a simple FragmentTransaction might look like this:

supportFragmentManager.commit {
   replace<ExampleFragment>(R.id.fragment_container)
   setReorderingAllowed(true)
   addToBackStack("name") // Name can be null
}

In this example, ExampleFragment replaces the fragment, if any, that is currently in the layout container identified by the R.id.fragment_container ID. Providing the fragment’s class to the replace() method lets the FragmentManager handle instantiation using its FragmentFactory. For more information, see the Provide dependencies to your fragments section.

setReorderingAllowed(true) optimizes the state changes of the fragments involved in the transaction so that animations and transitions work correctly. For more information on navigating with animations and transitions, see Fragment transactions and Navigate between fragments using animations.

Calling addToBackStack() commits the transaction to the back stack. The user can later reverse the transaction and bring back the previous fragment by tapping the Back button. If you added or removed multiple fragments within a single transaction, all those operations are undone when the back stack is popped. The optional name provided in the addToBackStack() call gives you the ability to pop back to a specific transaction using popBackStack().

If you don’t call addToBackStack() when you perform a transaction that removes a fragment, then the removed fragment is destroyed when the transaction is committed, and the user cannot navigate back to it. If you do call addToBackStack() when removing a fragment, then the fragment is only STOPPED and is later RESUMED when the user navigates back. Its view is destroyed in this case. For more information, see Fragment lifecycle.

References:

  • https://developer.android.com/guide/fragments/create
  • https://stackoverflow.com/questions/28929637/difference-and-uses-of-oncreate-oncreateview-and-onactivitycreated-in-fra