Fragments (Deep Dive)
Learn how to build modular and dynamic user interfaces using Android Fragments and manage their lifecycles.
Module 6: Fragments (Deep Dive)
Learning Objectives
By the end of this module, you’ll understand:
- Why Fragments were introduced
- Activity vs Fragment
- The Fragment lifecycle
- FragmentManager
- Fragment transactions
- Fragment back stack
- View lifecycle vs Fragment lifecycle
onCreateView()vsonViewCreated()onDestroyView()and memory leaks- Communication between Fragments
- Modern Fragment architecture
- Common interview questions
1. The Problem Before Fragments
Let’s go back to Android 1.0.
There were only Activities.
Imagine an email app.
Phone:
+----------------------+
| Inbox |
|----------------------|
| Email 1 |
| Email 2 |
| Email 3 |
+----------------------+
User taps Email 2.
Android launches another Activity.
InboxActivity
↓
EmailDetailActivity
Simple.
Now imagine a tablet.
Large screen:
+----------------------------------------+
| Inbox | Email Detail |
|------------|---------------------------|
| Email 1 | Hello... |
| Email 2 | |
| Email 3 | |
+----------------------------------------+
Oops.
Activities occupy the whole screen.
How can one Activity display two independent sections?
It can’t.
2. Google’s Solution
Google introduced Fragments in Android 3.0 (Honeycomb), initially to support tablets.
Instead of:
Activity
↓
Entire Screen
They introduced:
Activity
↓
Container
↓
Multiple Fragments
Like this:
+--------------------------------------+
Activity
+--------------------------------------+
| Fragment A | Fragment B |
+--------------------------------------+
One Activity could now host multiple UI pieces.
3. The House Analogy
This analogy is worth remembering.
Imagine a house.
House
↓
Kitchen
↓
Bedroom
↓
Bathroom
The house exists independently.
The rooms cannot.
Likewise:
Activity
↓
Fragment
↓
Fragment
↓
Fragment
The Activity owns the Fragments.
A Fragment cannot exist without an Activity host.
This is a fundamental rule.
4. Activity vs Fragment
| Activity | Fragment |
|---|---|
| Top-level UI controller | Modular UI component |
| Can exist independently | Must be attached to an Activity |
| Managed directly by Android | Managed by the Activity via FragmentManager |
| Has its own window | Shares the Activity’s window |
| Has a lifecycle | Has its own lifecycle plus a separate view lifecycle |
That last point is extremely important and explains many Fragment-related bugs.
5. Creating a Fragment
A simple Fragment:
class HomeFragment : Fragment(R.layout.fragment_home)
Or using onCreateView():
class HomeFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(
R.layout.fragment_home,
container,
false
)
}
}
Notice:
You don’t call onCreateView().
Android does.
6. Fragment Lifecycle
Many developers assume the Fragment lifecycle mirrors the Activity lifecycle.
It doesn’t.
Here’s the simplified sequence:
onAttach()
↓
onCreate()
↓
onCreateView()
↓
onViewCreated()
↓
onStart()
↓
onResume()
↓
Running
↓
onPause()
↓
onStop()
↓
onDestroyView()
↓
onDestroy()
↓
onDetach()
The key insight:
A Fragment has two lifecycles:
- The Fragment instance lifecycle.
- The Fragment’s View lifecycle.
Understanding the distinction is essential.
7. Why Two Lifecycles?
Consider this example.
A Fragment displays a list.
Fragment
↓
RecyclerView
The user navigates away.
With the Navigation Component, the Fragment instance might remain on the back stack, but its view hierarchy is destroyed to free memory.
That means:
Fragment Object
Still Exists
↓
View
Destroyed
When the user returns:
Existing Fragment
↓
New View Created
The same Fragment instance now owns a new view tree.
This is why the view lifecycle exists separately.
8. onAttach()
The Fragment is associated with its host Activity.
Activity
↓
Fragment Attached
At this point:
requireActivity()is valid.- The Fragment isn’t displaying a UI yet.
9. onCreate()
Initialize Fragment-level state.
Good for:
- Reading arguments.
- Creating non-UI objects.
- Initializing properties that survive view recreation.
Avoid touching views here—they don’t exist yet.
10. onCreateView()
This is where the UI hierarchy is created.
override fun onCreateView(...) : View
Responsibilities:
- Inflate the layout.
- Return the root view.
Think of it as:
“Build my UI.”
11. onViewCreated()
One of the most commonly used callbacks.
By now:
Layout
↓
Inflated
↓
Views Exist
Typical work:
- Set click listeners.
- Configure RecyclerViews.
- Observe ViewModel state using the view lifecycle.
- Initialize adapters.
Why not in onCreateView()?
Because onViewCreated() guarantees the view hierarchy is fully created, separating view inflation from view setup.
12. onDestroyView()
This is arguably the most important Fragment callback.
Imagine:
Fragment
↓
ViewBinding
↓
RecyclerView
↓
ImageViews
User navigates away.
Android destroys the views.
If your Fragment still holds references to those views, you leak memory.
A common pattern with View Binding:
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
Initialize in onCreateView():
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding.root
Then clear it:
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
This allows the old view hierarchy to be garbage collected.
13. FragmentManager
Who creates and destroys Fragments?
Not Android directly.
The host Activity uses a FragmentManager.
Activity
↓
FragmentManager
↓
Fragments
The FragmentManager:
- Adds Fragments.
- Removes Fragments.
- Replaces Fragments.
- Maintains the Fragment back stack.
Think of it as the Activity’s “Fragment controller.”
14. Fragment Transactions
Changes to Fragments occur through transactions.
Example:
supportFragmentManager.beginTransaction()
.replace(R.id.container, HomeFragment())
.commit()
What’s happening?
Current Fragment
↓
Replace
↓
New Fragment
The transaction isn’t applied immediately; it’s scheduled and committed.
15. The Fragment Back Stack
Suppose you navigate:
HomeFragment
↓
ProfileFragment
↓
SettingsFragment
Without adding to the back stack:
Replace
↓
Old Fragment Gone
Press Back:
The Activity closes.
With:
addToBackStack(null)
The sequence becomes:
Settings
↓
Back
↓
Profile
↓
Back
↓
Home
The FragmentManager manages this stack independently of the Activity stack.
16. Passing Data Between Fragments
Many beginners do this:
val fragment = ProfileFragment()
fragment.user = user // ❌
This is unsafe because Android may recreate the Fragment later.
Instead, use arguments:
val fragment = ProfileFragment().apply {
arguments = bundleOf(
"userId" to 42
)
}
Then read them:
val id = requireArguments().getInt("userId")
Today, the Navigation Component’s Safe Args (XML) or strongly typed navigation in Compose provides even safer approaches.
17. Fragment Communication
Imagine:
HomeFragment
↓
ProfileFragment
Should one Fragment call methods on the other directly?
Generally, no.
A better architecture:
Fragment
↓
Shared ViewModel
↓
Fragment
Or:
Fragment
↓
Activity
↓
Fragment
This keeps Fragments loosely coupled.
18. Common Fragment Bugs
Bug 1: Memory Leak
Fragment
↓
ViewBinding
↓
View Destroyed
↓
Binding Still Exists ❌
Solution:
Clear binding in onDestroyView().
Bug 2: Observing with the Wrong Lifecycle
Incorrect:
viewModel.data.observe(this) { ... }
The Fragment may outlive its view.
Correct:
viewModel.data.observe(viewLifecycleOwner) { ... }
Or, with Flow:
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { ... }
}
}
Tie UI observation to the view lifecycle, not the Fragment lifecycle.
Bug 3: Doing View Work Too Early
onCreate()
↓
textView.text = "Hello"
Crash.
Views don’t exist yet.
Do view-related work in onViewCreated().
19. Modern Android Architecture
Historically:
Many Activities
↓
One screen each
Then:
One Activity
↓
Many Fragments
Today, with Jetpack Compose:
One Activity
↓
Compose Navigation
↓
Composable Screens
Fragments haven’t disappeared—they’re still common in existing apps, hybrid projects, and certain integrations—but many new Compose-first apps avoid them for screen navigation.
Understanding Fragments remains essential because you’ll encounter them in production codebases for years to come.
Real-World Example
Imagine a shopping app.
MainActivity
↓
HomeFragment
↓
ProductFragment
↓
CartFragment
↓
CheckoutFragment
The Activity hosts navigation, while each Fragment encapsulates a feature.
If the user rotates the device while viewing a product:
- The Activity is recreated.
- The Fragment is recreated.
- The
ViewModelcan preserve the product data. - The view hierarchy is rebuilt.
The user experiences a seamless transition because the lifecycle is handled correctly.
Best Practices
- Keep Fragments focused on UI logic.
- Store screen state in a ViewModel, not in the Fragment.
- Use
onCreateView()only to inflate the layout. - Use
onViewCreated()to initialize and interact with views. - Always clear View Binding in
onDestroyView(). - Observe LiveData/Flow with
viewLifecycleOwner. - Use Fragment arguments for inputs.
- Avoid direct Fragment-to-Fragment communication.
Mental Model
Think of a Fragment as a reusable UI controller whose view can come and go multiple times during its lifetime.
Fragment Object
│
├─────────────── Lives Longer ───────────────┐
│ │
▼ ▼
Create View ──► Use View ──► Destroy View ──► Create New View
This single diagram explains why onDestroyView() exists, why viewLifecycleOwner matters, and why many Fragment bugs happen.
Interview Questions
- Why were Fragments introduced?
- Explain the difference between an Activity and a Fragment.
- Why does a Fragment have two lifecycles?
- What’s the difference between
onCreateView()andonViewCreated()? - Why is
onDestroyView()critical when using View Binding? - What is the role of
FragmentManager? - How does the Fragment back stack differ from the Activity back stack?
- Why shouldn’t Fragments communicate directly?
- Why should UI observations use
viewLifecycleOwnerinstead ofthis? - How has Jetpack Compose changed the role of Fragments?
Next Module: UI Development (XML & Jetpack Compose)
This is where everything we’ve learned comes together.
We’ll cover:
- How Android renders a screen from XML.
- The
Viewhierarchy and measure/layout/draw passes. ConstraintLayout,LinearLayout,FrameLayout, and when to use each.- Event handling and input processing.
- View Binding and Data Binding.
- Jetpack Compose fundamentals.
- Declarative UI vs imperative UI.
- State, recomposition, and why Compose is fundamentally different from XML.
This module will connect Android’s lifecycle with the actual UI you build every day, giving you a deep understanding of both the traditional View system and modern Compose.