Topic 23 of 28 · Android Native Developer

Topic 9 : Fragments, Intents/Intent Filters

Lesson TL;DRTopic 9: Fragments, Intents/Intent Filters 📖 12 min read · 🎯 intermediate · 🧭 Prerequisites: androidbuildingblocksivcontentproviders, inheritanceinjava Why this matters Up until now, you've probabl...
12 min read·intermediate·fragments · intents · intent-filters · android-ui

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.xml so 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:

TypeWhat it doesWhen to use
Explicit IntentNames the exact target component (Class)Navigating within your own app
Implicit IntentDescribes an action; system finds the handlerDelegating 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.

  1. Create MainActivity with two buttons: "Go to Profile" and "Open Website".
  2. "Go to Profile" starts a ProfileActivity using an explicit intent.
  3. "Open Website" fires an implicit intent with Intent.ACTION_VIEW pointing to https://developer.android.com.
  4. Register both activities in AndroidManifest.xml. Give ProfileActivity a custom Intent Filter with action com.example.myapp.VIEW_PROFILE.

Success criteria:

  • Tapping "Go to Profile" opens ProfileActivity directly (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 reaches ProfileActivity.

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.xml advertise what intents a component can handle, enabling both app-launcher registration and deep-link / cross-app integration.

📚 Further Reading

Like this topic? It’s one of 28 in Android Native Developer.

Block your seat for ₹2,500 and join the next cohort.