Comprehensive Guide to Android Fragments: Concepts, Architecture, Use Cases, and Workflow


What is Android Fragments?

Android Fragments are modular sections of an activity’s user interface (UI) that can be combined or reused in different activities. Introduced in Android 3.0 (API level 11) to address the challenges of supporting multiple screen sizes and orientations, fragments allow developers to build flexible, dynamic, and reusable UI components. Unlike activities, which represent entire screens, fragments encapsulate UI and behavior for a portion of the screen.

A fragment runs within an activity and has its own lifecycle, user interface, and event handlers. Fragments can be added, removed, replaced, or combined dynamically at runtime, enabling applications to modify their UI in response to user interaction or device characteristics without recreating the entire activity.


Major Use Cases of Android Fragments

1. Multi-pane UI on Tablets and Large Screens

Fragments facilitate responsive UI design by allowing developers to display multiple fragments side by side on tablets or foldable devices. For example, an email app can show the list of emails in one fragment and the email content in another, providing an optimized experience for larger screens.

2. Dynamic and Flexible UI Updates

On smaller devices like phones, fragments can be swapped or replaced within the same activity to show different content without needing multiple activities. This approach simplifies navigation and improves performance by avoiding activity transitions.

3. Reusable and Modular UI Components

Fragments encourage code modularity and reuse. Developers can encapsulate specific UI components with their logic into fragments and reuse them across different activities or even different apps, which reduces duplication and simplifies maintenance.

4. Handling Lifecycle Events Smoothly

Fragments provide lifecycle methods closely tied to the hosting activity, but with their own granular callbacks to manage UI state, resource allocation, and cleanup. This makes it easier to manage complex UI states such as handling orientation changes or backgrounding.

5. Backstack and Navigation Management

Using the FragmentManager and fragment transactions, developers can build complex navigation flows inside a single activity, maintain a fragment backstack for navigation, and implement transitions and animations between fragments.

6. Integration with ViewModel and LiveData

Fragments often work together with Android Architecture Components like ViewModel and LiveData to manage UI-related data in a lifecycle-aware manner. This combination enhances data sharing between fragments and improves separation of concerns.


How Android Fragments Work Along with Architecture

Fragment Lifecycle and Interaction with Activity

The fragment lifecycle is tightly coupled with its host activity’s lifecycle but also has distinct callbacks to manage the fragment’s UI and state independently:

  • onAttach(Context): Called when the fragment is attached to its host activity.
  • onCreate(Bundle): Initialization logic for the fragment, including retained state.
  • onCreateView(LayoutInflater, ViewGroup, Bundle): Inflates the fragment’s UI layout.
  • onViewCreated(View, Bundle): Called after the fragment’s view hierarchy has been created.
  • onActivityCreated(Bundle): Signals that the activity and fragment’s UI are ready.
  • onStart() / onResume(): Fragment becomes visible and interactive.
  • onPause() / onStop(): Fragment loses focus or becomes invisible.
  • onDestroyView(): Cleans up the fragment’s UI resources.
  • onDestroy(): Final cleanup before the fragment is destroyed.
  • onDetach(): Fragment detaches from the host activity.

Fragment Architecture in Android Apps

  • Activity: The container or host of one or multiple fragments, responsible for overall app navigation and interaction.
  • Fragment: Self-contained UI components with their own lifecycle and UI, managed by the activity.
  • FragmentManager: API responsible for managing fragment operations like add, replace, remove, and managing the fragment backstack.
  • FragmentTransaction: Represents a set of changes to fragments to be performed atomically.
  • ViewModel: (Optional) Architecture component used to share UI data across fragments or between fragment and activity without tight coupling.

Fragment Transactions and Backstack

FragmentManager enables developers to perform atomic transactions involving multiple fragments. Transactions can:

  • Add: Insert a new fragment into the UI.
  • Replace: Swap out one fragment for another.
  • Remove: Delete a fragment from the UI.
  • AddToBackStack: Preserve fragment transaction history to allow back navigation.

Backstack management mimics activity stack behavior but at a fragment level, providing granular control over UI state and navigation.


Basic Workflow of Android Fragments

  1. Create Fragment Class: Define a new fragment by extending Fragment or its subclasses.
  2. Define Fragment Layout: Create an XML layout file describing the UI of the fragment.
  3. Add Container to Activity Layout: Define a container view (e.g., FrameLayout) in the activity layout where fragments will be displayed.
  4. Add or Replace Fragments Programmatically: Use FragmentManager and FragmentTransaction to add, replace, or remove fragments.
  5. Manage Fragment Lifecycle: Implement lifecycle callbacks to initialize data, handle UI state restoration, and release resources.
  6. Handle Communication: Use interfaces, ViewModel, or shared ViewModel to enable communication between fragments and activities or between fragments.
  7. Manage Backstack and Navigation: Use fragment backstack to provide a seamless navigation experience within the activity.

Step-by-Step Getting Started Guide for Android Fragments

Step 1: Create a Fragment Class

Create a new class extending Fragment and override onCreateView() to inflate the fragment’s layout.

public class ExampleFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, 
                             @Nullable ViewGroup container, 
                             @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_example, container, false);
    }
}

Step 2: Define the Fragment Layout

Create a layout XML file (res/layout/fragment_example.xml) with UI elements:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" 
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">
    
    <TextView
        android:id="@+id/text_example"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Welcome to the Fragment!" />
    
    <Button
        android:id="@+id/button_action"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click Me" />
</LinearLayout>

Step 3: Add Fragment Container to Activity Layout

In the activity’s layout (activity_main.xml), add a container where the fragment will be placed:

<FrameLayout
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Step 4: Add Fragment to Activity Programmatically

In the activity’s onCreate() method, load the fragment into the container:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
            .add(R.id.fragment_container, new ExampleFragment())
            .commit();
    }
}

Step 5: Replace or Remove Fragments

To replace the current fragment with another fragment:

Fragment newFragment = new AnotherFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null); // Optional: adds to backstack
transaction.commit();

Step 6: Communicate Between Fragment and Activity

Define an interface inside your fragment:

public interface OnFragmentInteractionListener {
    void onFragmentInteraction(String data);
}

Make the hosting activity implement this interface:

public class MainActivity extends AppCompatActivity implements ExampleFragment.OnFragmentInteractionListener {
    @Override
    public void onFragmentInteraction(String data) {
        Toast.makeText(this, "Data received: " + data, Toast.LENGTH_SHORT).show();
    }
}

Invoke the callback from fragment when needed:

OnFragmentInteractionListener listener;

@Override
public void onAttach(@NonNull Context context) {
    super.onAttach(context);
    if (context instanceof OnFragmentInteractionListener) {
        listener = (OnFragmentInteractionListener) context;
    } else {
        throw new RuntimeException(context.toString() + " must implement OnFragmentInteractionListener");
    }
}

Advanced Concepts

Fragment Retention Across Configuration Changes

Fragments can retain their instance across configuration changes (like device rotation) by calling:

setRetainInstance(true);

This prevents the fragment from being destroyed and recreated, useful for retaining expensive data or background tasks.

Using ViewModel with Fragments

By using ViewModel scoped to activity or fragment, data survives configuration changes and can be shared between fragments and activities in a lifecycle-aware manner:

MyViewModel viewModel = new ViewModelProvider(requireActivity()).get(MyViewModel.class);

Navigation Component and Fragments

Android Jetpack Navigation Component simplifies fragment navigation, backstack, and argument passing with a declarative navigation graph, reducing boilerplate and improving consistency.