Topic 9: Fragments, Intents/Intent Filters
📖 12 min read · 🎯 intermediate · 🧭 Prerequisites: android-building-blocks-iv-content-providers, inheritance-in-java
Why this matters
Up until now, you've probably been thinking of your app as a bunch of separate screens — tap a button, go to a new screen, tap back, return. That works. But it starts to feel clunky fast, especially on tablets or when you need parts of your screen to update without replacing the whole thing. That's where Fragments come in. And when any two parts of your app — or even two completely different apps — need to talk to each other, Android has a built-in messaging system called Intents. These two tools together are what make Android apps feel fluid and connected, not just a stack of pages.
What You'll Learn
- Understand what Fragments are and why they exist as reusable, modular UI units
- Build a two-fragment master/detail pattern wired together through an interface callback
- Use Explicit Intents to start a specific activity inside your own app
- Use Implicit Intents to delegate actions (like opening a URL) to the wider Android ecosystem
- Declare Intent Filters in
AndroidManifest.xmlso other apps can invoke your components
The Analogy
Think of your Android app as a modular office building. Fragments are like moveable partition walls — you can slide them in, slide them out, swap them with different rooms, and stack them back-to-back, all while the building (the Activity) stays standing. Intents are the interoffice memos that travel between rooms: an explicit memo says "deliver this to Room 204 specifically," while an implicit memo says "whoever handles printing requests, please take care of this." Intent Filters are the job postings on each room's door — they advertise what kinds of memos that room is qualified to receive. Together these three mechanisms turn a rigid floor plan into a dynamic, interconnected workspace.
Chapter 1: Fragments — Modular, Reusable UI
A Fragment represents a reusable portion of your application's UI. It is modular and can be embedded in activities, letting you build dynamic and flexible interfaces. Fragments can be added, removed, or replaced while the activity is running — no restart required.
Key benefits:
- Modularity — divide your UI into smaller, self-contained components
- Flexibility — swap UI components dynamically at runtime
- Reusability — the same Fragment can appear in multiple activities or even different apps
Fragment lifecycle basics
A Fragment lives inside a host Activity. Its view is created in onCreateView(), and it is destroyed when removed from the back stack. The host Activity manages the Fragment back stack via FragmentManager and FragmentTransaction.
flowchart TD
A[Activity Created] --> B[FragmentTransaction.add()]
B --> C[Fragment.onCreateView()]
C --> D[Fragment visible to user]
D --> E{User action?}
E -- replace --> F[FragmentTransaction.replace()]
F --> G[Fragment.onDestroyView()]
G --> H[New Fragment.onCreateView()]
E -- back pressed --> I[FragmentManager pops back stack]
I --> D
Chapter 2: Building a Two-Fragment Master/Detail Example
This walkthrough creates a ListFragment that shows selectable items and a DetailFragment that displays the chosen item. A callback interface keeps the two fragments decoupled.
Step 1 — Define the Fragment layouts
fragment_list.xml
<!-- res/layout/fragment_list.xml -->
<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">
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
fragment_detail.xml
<!-- res/layout/fragment_detail.xml -->
<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/detail_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Detail"
android:textSize="18sp" />
</LinearLayout>
Step 2 — Create the Fragment classes
ListFragment.java
package com.example.myapp;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class ListFragment extends Fragment {
private String[] items = {"Item 1", "Item 2", "Item 3"};
private OnItemSelectedListener listener;
public interface OnItemSelectedListener {
void onItemSelected(String item);
}
public void setOnItemSelectedListener(OnItemSelectedListener listener) {
this.listener = listener;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_list, container, false);
ListView listView = view.findViewById(R.id.list_view);
ArrayAdapter<String> adapter = new ArrayAdapter<>(
getContext(),
android.R.layout.simple_list_item_1,
items);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
if (listener != null) {
listener.onItemSelected(items[position]);
}
}
});
return view;
}
}
DetailFragment.java
package com.example.myapp;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class DetailFragment extends Fragment {
private TextView detailText;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_detail, container, false);
detailText = view.findViewById(R.id.detail_text);
return view;
}
public void setDetailText(String detail) {
if (detailText != null) {
detailText.setText(detail);
}
}
}
Step 3 — Host both fragments in MainActivity
MainActivity.java
package com.example.myapp;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentTransaction;
public class MainActivity extends AppCompatActivity
implements ListFragment.OnItemSelectedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListFragment listFragment = new ListFragment();
listFragment.setOnItemSelectedListener(this);
FragmentTransaction transaction =
getSupportFragmentManager().beginTransaction();
transaction.add(R.id.fragment_container, listFragment);
transaction.commit();
}
@Override
public void onItemSelected(String item) {
DetailFragment detailFragment = new DetailFragment();
FragmentTransaction transaction =
getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, detailFragment);
transaction.addToBackStack(null);
transaction.commit();
// executePendingTransactions() ensures the fragment view exists
// before we call setDetailText()
getSupportFragmentManager().executePendingTransactions();
detailFragment.setDetailText(item);
}
}
Step 4 — The host layout
activity_main.xml
<!-- res/layout/activity_main.xml -->
<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">
</FrameLayout>
A FrameLayout with a stable id is all the Activity needs — the FragmentManager handles everything that gets loaded inside it.
Chapter 3: Intents — Android's Messaging System
Intents are messaging objects used to request actions from other app components. An Intent can:
- Start an Activity — navigate to a new screen
- Start a Service — trigger background work
- Deliver a Broadcast — notify multiple components of a system event
There are two varieties:
| Type | What it does | When to use |
|---|---|---|
| Explicit Intent | Names the exact target component (Class) | Navigating within your own app |
| Implicit Intent | Describes an action; system finds the handler | Delegating to the OS or other apps |
Chapter 4: Explicit Intents
An explicit intent hard-codes the destination component. It is the standard way to move between screens inside a single app.
FirstActivity.java
package com.example.myapp;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
}
});
}
}
SecondActivity.java
package com.example.myapp;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}
}
activity_first.xml
<!-- res/layout/activity_first.xml -->
<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">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Go to Second Activity" />
</LinearLayout>
The constructor new Intent(FirstActivity.this, SecondActivity.class) explicitly targets SecondActivity — the system has no ambiguity about where to route this memo.
Chapter 5: Implicit Intents
An implicit intent describes what you want to do without naming a specific component. The Android system inspects all installed apps' Intent Filters and presents a chooser (or silently routes to the only match).
Example: Opening a web page
// MainActivity.java
package com.example.myapp;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.example.com"));
startActivity(intent);
}
});
}
}
activity_main.xml (implicit intent demo)
<!-- res/layout/activity_main.xml -->
<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">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Open Web Page" />
</LinearLayout>
Intent.ACTION_VIEW with a https:// URI tells Android "I want to view something at this URL — figure out who can handle that." Chrome, Firefox, or whatever the user's default browser is will open.
Chapter 6: Intent Filters
Intent Filters are declarations inside AndroidManifest.xml that advertise what kinds of intents a component can handle. They are the "job postings on the door" that let the Android system route implicit intents correctly.
An Intent Filter can specify:
<action>— the action name the component responds to (e.g.,android.intent.action.MAIN)<category>— further qualifies the action (e.g.,android.intent.category.LAUNCHER)<data>— URI scheme, MIME type, or host the component accepts
Declaring Intent Filters in AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application
android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="com.example.myapp.VIEW_SECOND_ACTIVITY" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
The MAIN + LAUNCHER filter on MainActivity tells the OS this is the app's entry point and should appear in the launcher. The custom action com.example.myapp.VIEW_SECOND_ACTIVITY on SecondActivity makes it reachable via an implicit intent that uses that action string.
Starting SecondActivity with an Implicit Intent (using the custom filter)
// MainActivity.java
package com.example.myapp;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.myapp.VIEW_SECOND_ACTIVITY");
startActivity(intent);
}
});
}
}
No class reference is used here — just the action string. Android matches it against the manifest, finds SecondActivity's filter, and launches it. This is exactly how deep links and cross-app integrations work at scale.
sequenceDiagram
participant App as Caller App
participant OS as Android OS
participant Manifest as AndroidManifest.xml
participant Target as SecondActivity
App->>OS: startActivity(implicit Intent)
OS->>Manifest: scan all Intent Filters
Manifest-->>OS: match found: SecondActivity
OS->>Target: launch SecondActivity
🧪 Try It Yourself
Task: Build a two-screen app that uses both an explicit and an implicit intent.
- Create
MainActivitywith two buttons: "Go to Profile" and "Open Website". - "Go to Profile" starts a
ProfileActivityusing an explicit intent. - "Open Website" fires an implicit intent with
Intent.ACTION_VIEWpointing tohttps://developer.android.com. - Register both activities in
AndroidManifest.xml. GiveProfileActivitya custom Intent Filter with actioncom.example.myapp.VIEW_PROFILE.
Success criteria:
- Tapping "Go to Profile" opens
ProfileActivitydirectly (no chooser). - Tapping "Open Website" opens the Android developer docs in a browser.
- Adding a third button that fires
new Intent("com.example.myapp.VIEW_PROFILE")also reachesProfileActivity.
Starter snippet for MainActivity:
Button goToProfile = findViewById(R.id.btn_profile);
Button openWeb = findViewById(R.id.btn_web);
goToProfile.setOnClickListener(v -> {
Intent explicit = new Intent(MainActivity.this, ProfileActivity.class);
startActivity(explicit);
});
openWeb.setOnClickListener(v -> {
Intent implicit = new Intent(Intent.ACTION_VIEW);
implicit.setData(Uri.parse("https://developer.android.com"));
startActivity(implicit);
});
🔍 Checkpoint Quiz
Q1. A Fragment's view is created inside which lifecycle method, and what does it return?
A) onCreate() — returns a Bundle
B) onCreateView() — returns a View
C) onStart() — returns a ViewGroup
D) onAttach() — returns a Context
Q2. Given this code, what happens when the user taps the button?
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.example.com"));
startActivity(intent);
A) It crashes because no target class is specified
B) It opens https://www.example.com in the device's default browser
C) It navigates to SecondActivity
D) It sends a broadcast to all registered receivers
Q3. What is the purpose of calling transaction.addToBackStack(null) before committing a FragmentTransaction?
A) It adds the fragment to a saved instance state bundle B) It ensures the fragment is retained on device rotation C) It allows the user to navigate back to the previous fragment by pressing the back button D) It prevents the fragment from being replaced
Q4. You want your app to be launchable from the Android home screen. Which combination of <action> and <category> must appear in your main activity's Intent Filter in AndroidManifest.xml?
A) ACTION_DEFAULT + CATEGORY_MAIN
B) ACTION_LAUNCH + CATEGORY_HOME
C) ACTION_MAIN + CATEGORY_LAUNCHER
D) ACTION_START + CATEGORY_DEFAULT
A1. B — onCreateView() is the Fragment lifecycle method responsible for inflating and returning the fragment's UI as a View.
A2. B — This is an implicit intent using ACTION_VIEW with an https:// URI. The Android system routes it to the installed browser, which opens the URL.
A3. C — addToBackStack(null) pushes the current fragment state onto the back stack so pressing the system back button pops the transaction and restores the previous fragment, rather than finishing the activity.
A4. C — The combination android.intent.action.MAIN + android.intent.category.LAUNCHER is what tells the Android launcher to display the app icon and use that activity as the entry point.
🪞 Recap
- A Fragment is a reusable, modular UI unit that lives inside a host Activity and can be added, replaced, or removed at runtime via
FragmentTransaction. - Fragments communicate with their host Activity through callback interfaces, keeping UI components decoupled.
- An Explicit Intent names the exact target component (
new Intent(this, SomeActivity.class)) and is used for intra-app navigation. - An Implicit Intent describes an action and data (e.g.,
ACTION_VIEW+ URI) and lets the Android system route it to any capable component. - Intent Filters in
AndroidManifest.xmladvertise what intents a component can handle, enabling both app-launcher registration and deep-link / cross-app integration.
📚 Further Reading
- Android Fragments guide — the official reference on Fragment lifecycle, back stack, and best practices
- Intents and Intent Filters — comprehensive Android docs covering explicit, implicit, pending intents, and filter matching rules
- Common Intents reference — a catalog of standard implicit intents (maps, camera, dialer, browser, etc.) you can fire without knowing the target app
- ⬅️ Previous: Inheritance in Java
- ➡️ Next: Strings in Java