Fragments & Navigation

Reusable UI modules, fragment transactions, and Jetpack Navigation patterns

Fragment Lifecycle Transactions Nav Component Bottom & Drawer Nav

Table of Contents

1Fragment Lifecycle

A Fragment is a reusable portion of UI with its own lifecycle, hosted inside an Activity. Fragments let you build flexible layouts — especially for tablets (master/detail) and single-pane phones (swap screens in one activity).

Fragment vs Activity: An Activity owns the window; a Fragment owns a slice of that window. Multiple fragments can live in one activity, and each fragment can be added, removed, or replaced independently.

Why use Fragments?

  • Modular UI — split screens into reusable pieces (Home, Profile, Settings)
  • Adaptive layouts — show two fragments side-by-side on tablets, one at a time on phones
  • Back stack — navigate between screens without launching new activities
  • Works with Jetpack Navigation, ViewPager2, and Bottom Navigation

Fragment Lifecycle States

[Fragment created] ↓ onAttach() → Fragment linked to host Activity ↓ onCreate() → Initialize non-UI resources ↓ onCreateView() → Inflate layout (return View) ↓ onViewCreated() → Setup views, listeners, observers ↓ onStart() → Fragment visible (not yet interactive) ↓ onResume() → Fragment active and interactive ↓ [User navigates away / fragment hidden] ↓ onPause() → onStop() → onDestroyView() → onDestroy() → onDetach() Back stack note: replace() + addToBackStack() → Back button reverses transaction without addToBackStack() → Back exits the Activity

Key Lifecycle Callbacks

CallbackWhen CalledTypical Use
onAttach()Fragment associated with ActivityGet Activity reference (prefer requireContext() later)
onCreate()Fragment instance createdRead arguments, init ViewModel
onCreateView()Build UIInflate layout, return root View
onViewCreated()View hierarchy readyFind views, set click listeners, observe LiveData
onDestroyView()View being destroyedClear view references to avoid memory leaks
onDetach()Fragment unlinked from ActivityFinal cleanup

Logging the Fragment Lifecycle

Kotlin — HomeFragment.ktclass HomeFragment : Fragment(R.layout.fragment_home) { private val TAG = "HomeFragment" override fun onAttach(context: Context) { super.onAttach(context) Log.d(TAG, "onAttach") } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Log.d(TAG, "onCreate") } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) Log.d(TAG, "onViewCreated") } override fun onStart() { super.onStart() Log.d(TAG, "onStart") } override fun onResume() { super.onResume() Log.d(TAG, "onResume") } override fun onPause() { Log.d(TAG, "onPause") super.onPause() } override fun onDestroyView() { Log.d(TAG, "onDestroyView") super.onDestroyView() } }

2Creating Fragments

Modern Android uses the AndroidX Fragment class from androidx.fragment:fragment-ktx. You create a Kotlin class, a layout XML file, and host it in an Activity container.

Step 1 — Create the layout

XML — res/layout/fragment_home.xml<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center" android:padding="24dp"> <TextView android:id="@+id/tvWelcome" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/welcome_home" android:textSize="22sp" android:textStyle="bold" /> <Button android:id="@+id/btnGoProfile" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="Go to Profile" /> </LinearLayout>

Step 2 — Create the Fragment class

Kotlin — HomeFragment.ktclass HomeFragment : Fragment(R.layout.fragment_home) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) view.findViewById<Button>(R.id.btnGoProfile).setOnClickListener { parentFragmentManager.beginTransaction() .replace(R.id.fragment_container, ProfileFragment()) .addToBackStack(null) .commit() } } companion object { fun newInstance(userName: String): HomeFragment { return HomeFragment().apply { arguments = Bundle().apply { putString("user_name", userName) } } } } }

Step 3 — Add a container in the Activity layout

XML — res/layout/activity_main.xml<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent" />

Step 4 — Load the Fragment in MainActivity

Kotlin — MainActivity.ktclass MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) if (savedInstanceState == null) { supportFragmentManager.beginTransaction() .replace(R.id.fragment_container, HomeFragment.newInstance("Nikhil")) .commit() } } }

Passing data with arguments

Kotlin — Read arguments safelyoverride fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val userName = arguments?.getString("user_name") ?: "Guest" view.findViewById<TextView>(R.id.tvWelcome).text = "Welcome, $userName!" }

3Fragment Transactions

A FragmentTransaction is a set of changes (add, replace, remove, hide, show) applied atomically. You obtain it from supportFragmentManager (Activity) or parentFragmentManager (Fragment).

Transaction operations

MethodEffectCommon Use
add(containerId, fragment)Inserts fragment into containerStack multiple fragments (rare)
replace(containerId, fragment)Removes existing, adds newScreen navigation (most common)
remove(fragment)Destroys fragmentClose overlay panels
hide(fragment) / show(fragment)Toggle visibility, keep stateTab-like switching without recreation
addToBackStack(name)Reversible on Back pressMulti-step flows inside one Activity

Basic replace with back stack

Kotlin — Navigate to SettingsFragmentsupportFragmentManager.beginTransaction() .setCustomAnimations( R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right ) .replace(R.id.fragment_container, SettingsFragment()) .addToBackStack("settings") .commit()

commit() vs commitAllowingStateLoss()

  • commit() — Safe default; throws if called after onSaveInstanceState()
  • commitAllowingStateLoss() — Use only when unavoidable; may lose state on process death
  • Best practice: Perform transactions in response to user actions, not async callbacks after rotation

FragmentManager vs childFragmentManager

Kotlin — Nested fragments// Activity hosts parent fragment supportFragmentManager.beginTransaction() .replace(R.id.fragment_container, ParentFragment()) .commit() // Inside ParentFragment — host child fragments childFragmentManager.beginTransaction() .replace(R.id.child_container, ChildFragment()) .commit()

5Bottom Navigation

Bottom Navigation displays 3–5 top-level destinations at the bottom of the screen. It pairs naturally with the Navigation Component — each menu item maps to a destination in your nav graph.

Layout with BottomNavigationView + NavHost

XML — activity_main.xml<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.fragment.app.FragmentContainerView android:id="@+id/nav_host_fragment" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="0dp" android:layout_height="0dp" app:defaultNavHost="true" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toTopOf="@id/bottom_nav" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:navGraph="@navigation/nav_graph" /> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/bottom_nav" android:layout_width="0dp" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:menu="@menu/bottom_nav_menu" /> </androidx.constraintlayout.widget.ConstraintLayout>

Bottom nav menu

XML — res/menu/bottom_nav_menu.xml<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/homeFragment" android:icon="@drawable/ic_home" android:title="@string/home" /> <item android:id="@+id/searchFragment" android:icon="@drawable/ic_search" android:title="@string/search" /> <item android:id="@+id/profileFragment" android:icon="@drawable/ic_profile" android:title="@string/profile" /> </menu>

Wire BottomNavigationView to NavController

Kotlin — MainActivity.ktval navController = findNavController(R.id.nav_host_fragment) val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav) bottomNav.setupWithNavController(navController)

Tip: Menu item IDs must match fragment destination IDs in nav_graph.xml. Use app:popUpTo and app:popUpToSaveState on bottom-nav destinations to preserve each tab's state when switching.

Preserve tab state in nav graph

XML — Bottom nav destination options<fragment android:id="@+id/homeFragment" android:name="com.example.app.HomeFragment" android:label="Home" app:popUpTo="@id/nav_graph" app:popUpToSaveState="true" app:launchSingleTop="true" app:restoreState="true" />

6Drawer Navigation

A Navigation Drawer slides in from the left edge and exposes many destinations without cluttering the main UI. Use DrawerLayout + NavigationView with the Navigation Component for seamless integration.

Drawer layout structure

XML — activity_main.xml with DrawerLayout<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/toolbar" android:layout_width="0dp" android:layout_height="?attr/actionBarSize" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" /> <androidx.fragment.app.FragmentContainerView android:id="@+id/nav_host_fragment" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="0dp" android:layout_height="0dp" app:defaultNavHost="true" app:layout_constraintTop_toBottomOf="@id/toolbar" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:navGraph="@navigation/nav_graph" /> </androidx.constraintlayout.widget.ConstraintLayout> <com.google.android.material.navigation.NavigationView android:id="@+id/nav_view" android:layout_width="280dp" android:layout_height="match_parent" android:layout_gravity="start" app:headerLayout="@layout/nav_header" app:menu="@menu/drawer_menu" /> </androidx.drawerlayout.widget.DrawerLayout>

Drawer menu

XML — res/menu/drawer_menu.xml<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:checkableBehavior="single"> <item android:id="@+id/homeFragment" android:icon="@drawable/ic_home" android:title="@string/home" /> <item android:id="@+id/settingsFragment" android:icon="@drawable/ic_settings" android:title="@string/settings" /> <item android:id="@+id/aboutFragment" android:icon="@drawable/ic_info" android:title="@string/about" /> </group> </menu>

Connect drawer, toolbar, and NavController

Kotlin — MainActivity.kt (Drawer setup)class MainActivity : AppCompatActivity() { private lateinit var appBarConfiguration: AppBarConfiguration override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val toolbar = findViewById<MaterialToolbar>(R.id.toolbar) setSupportActionBar(toolbar) val drawerLayout = findViewById<DrawerLayout>(R.id.drawer_layout) val navView = findViewById<NavigationView>(R.id.nav_view) val navController = findNavController(R.id.nav_host_fragment) appBarConfiguration = AppBarConfiguration( setOf(R.id.homeFragment, R.id.settingsFragment, R.id.aboutFragment), drawerLayout ) setupActionBarWithNavController(navController, appBarConfiguration) navView.setupWithNavController(navController) } override fun onSupportNavigateUp(): Boolean { val navController = findNavController(R.id.nav_host_fragment) return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() } }

Bottom Nav vs Drawer — when to use which

PatternBest ForMax Destinations
Bottom NavigationPrimary app sections users switch between often3–5 items
Navigation DrawerMany destinations, settings, secondary screens5+ items
CombinedBottom nav for main tabs + drawer for settings/aboutFlexible

7Hands-On Exercises

1

Create a single-Activity app with two fragments: HomeFragment and ProfileFragment. Use a button in Home to navigate to Profile with replace() and addToBackStack(). Press Back to return.

2

Add Log statements to every lifecycle method in both fragments. Switch between them and observe the callback order in Logcat.

3

Pass a username from Home to Profile using a Bundle argument. Display it in a TextView on the Profile screen.

4

Refactor the app to use the Navigation Component: create nav_graph.xml, add a NavHostFragment, and navigate with findNavController().navigate().

5

Add a Bottom Navigation bar with three tabs (Home, Search, Profile). Wire it to the nav graph using setupWithNavController().

6

Replace Bottom Navigation with a Navigation Drawer. Add a MaterialToolbar with hamburger icon, header layout, and drawer menu items for Home, Settings, and About.

7

Bonus: Combine Bottom Navigation (3 main tabs) with a Drawer (Settings + Logout). Ensure the Up button and Back button behave correctly on nested screens.

Fragments & Navigation MCQ Practice

10 Basic MCQs 10 Advanced MCQs

10 Basic Fragments & Navigation MCQs

1

Fragment represents?

AReusable UI portion in an Activity
BBackground service
CDatabase table
DGradle module
Explanation: Fragments modularize UI hosted by FragmentActivity/AppCompatActivity.
2

FragmentManager handles?

AAdding/replacing Fragments
BAPK signing
CSDK download
DLint only
Explanation: FragmentManager executes transactions and back stack.
3

Jetpack Navigation uses?

ANavController and nav graph XML
BOnly manual FragmentTransaction
CADB
DWear OS
Explanation: Navigation Component defines destinations and actions in a graph.
4

BottomNavigationView typically switches?

ATop-level destinations / tabs
BGradle variants
CKernel modules
DPermissions only
Explanation: Bottom nav maps menu items to nav graph destinations.
5

onCreateView in Fragment returns?

ARoot View of fragment layout
BIntent
CService binder
DGradle config
Explanation: Inflates layout and returns the fragment's view hierarchy.
6

NavHostFragment role?

AContainer hosting NavController graph
BLauncher icon
CDatabase helper
DProGuard
Explanation: NavHostFragment is the swap container for destinations.
7

DrawerLayout often pairs with?

ANavigationView for side menu
BRecyclerView only
CSQLite
DCameraX
Explanation: Material drawer uses NavigationView + AppBarConfiguration.
8

Fragment lifecycle tied to?

AHosting Activity lifecycle
BLinux kernel only
CPlay Store
DIndependent always
Explanation: Fragment callbacks interleave with Activity (onStart, onResume, etc.).
9

Safe Args plugin provides?

AType-safe navigation arguments
BFaster emulator
CAuto screenshots
DFree hosting
Explanation: Safe Args generates Directions classes for nav arguments.
10

replace() vs add() in transaction?

Areplace removes container fragment; add stacks
BIdentical
COnly add legal
DNeither works
Explanation: replace swaps current; add can stack multiple in same container.

10 Advanced Fragments & Navigation MCQs

11

onDestroyView Fragment should?

ANull out view binding references
BStart new Activity always
CSkip super
DCommit retained fragment
Explanation: Views destroyed on destroyView — clear binding to prevent leaks.
12

popBackStack()?

APops Fragment transactions from back stack
BUninstalls app
CClears Logcat
DRevokes permission
Explanation: addToBackStack enables reverse navigation via Back.
13

Single-Activity architecture means?

AOne Activity hosts multiple Fragments
BOne Fragment total
CNo nav graph
DNo ViewModel
Explanation: Navigation moves between fragments inside one Activity shell.
14

Deep links in nav graph?

AdeepLink attribute on destination
BOnly implicit intents banned
CGradle task
Dstrings.xml
Explanation: Nav graph can declare URI patterns matched by NavController.
15

Fragment result API used for?

AParent-child fragment communication
BPlay billing
CDex merging
DHAL access
Explanation: setFragmentResult delivers bundles to listeners in same Activity.
16

ViewPager2 with Fragments uses?

AFragmentStateAdapter
BArrayAdapter
CCursorAdapter
DServiceConnection
Explanation: FragmentStateAdapter supplies Fragments for each page.
17

Navigation UI setupWithNavController?

AWires BottomNav/Toolbar to NavController
BStarts emulator
CMerges manifest
DRuns lint
Explanation: Automatically handles destination selection and Up button.
18

Retained Fragment (deprecated pattern)?

ASurvived rotation before ViewModel
BNever existed
CSame as Service
DReplaces NavHost
Explanation: ViewModel now preferred for surviving config changes.
19

Multiple back stacks Bottom Nav (Navigation 2.4+)?

Asave/restore state per tab
BImpossible
CRequires separate apps
DADB only
Explanation: Navigation supports independent back stacks for each top-level tab.
20

DialogFragment advantage?

ALifecycle-aware modal UI
BFaster RecyclerView
CNative HAL
DReplaces SQLite
Explanation: DialogFragment handles config changes and FragmentManager properly.
Click an option to select, then check answers.

Fragments & Navigation Interview Q&A

15 topic-focused questions for interviews and revision.

1Why use Fragments instead of many Activities?medium
Answer: Reuse UI on phones/tablets, share ViewModels, single-Activity nav, bottom tabs without Activity overhead.
2Explain Fragment lifecycle vs Activity.medium
Answer: Fragment has onAttach, onCreate, onCreateView, onViewCreated, onDestroyView — view can be destroyed while fragment instance exists.
3What is a FragmentTransaction?easy
Answer: Atomic set of operations (add/replace/hide) committed to FragmentManager; optional back stack entry.
4How does Jetpack Navigation simplify navigation?medium
Answer: Central nav graph, type-safe args, deep links, animations, and NavController handles back stack consistently.
5Setup Bottom Navigation with Navigation Component.medium
Answer: Menu items match destination IDs; NavHost in layout; setupWithNavController connects BottomNavigationView.
6Implement Navigation Drawer steps.medium
Answer: DrawerLayout + NavigationView; AppBarConfiguration with drawer destinations; NavigationUI.setupWithNavController.
7When to use addToBackStack?easy
Answer: When user should press Back to undo fragment transaction (e.g., master-detail drill-down).
8Common Fragment crash: not attached to context.hard
Answer: Access context after onDetach; use viewLifecycleOwner, requireContext() only when attached, or lifecycle-aware observers.
9Difference between child FragmentManager and parent.hard
Answer: Child FM manages nested fragments inside a parent fragment; use getChildFragmentManager for nested cases.
10What is Safe Args?medium
Answer: Gradle plugin generating Kotlin/Java classes for nav arguments — compile-time safety vs raw bundles.
11Single-Activity pros and cons.medium
Answer: Pros: shared transitions, simpler task stack, ViewModel scope. Cons: learning curve, legacy code migration.
12How do Fragments communicate?medium
Answer: Shared ViewModel, Fragment Result API, interface callbacks to Activity, or Navigation args — avoid direct references.
13onDestroyView vs onDestroy in Fragment.medium
Answer: onDestroyView tears down UI; onDestroy final fragment teardown — clear bindings in onDestroyView.
14Navigation deep linking example.hard
Answer: https://app.example/user/{id} mapped in nav graph opens UserFragment with argument.
15Testing navigation.hard
Answer: Navigation Testing API with TestNavHostController to verify destination changes on actions.