Topic 17 of 28 · Android Native Developer

Topic 3 : Android Application Components required to make an Application

Lesson TL;DRTopic 3: Android Application Components required to make an Application 📖 13 min read · 🎯 beginner · 🧭 Prerequisites: androidenvironmentsetuphelloworld, introductiontoandroidosjavaprogramminglangua...
13 min read·beginner·android · activities · services · broadcast-receivers

Topic 3: Android Application Components required to make an Application

📖 13 min read · 🎯 beginner · 🧭 Prerequisites: android-environment-set-up-hello-world, introduction-to-android-os-java-programming-language

Why this matters

Here's the thing — every Android app you've ever tapped on your phone, whether it's WhatsApp, YouTube, or a simple calculator, is built from the same five building blocks: Activities, Services, Broadcast Receivers, Content Providers, and Intents. That's it. Before you write a single line of code, you need to know what these components are and what role each one plays. Skip this, and you'll keep getting lost wondering why your app isn't working. Understand it, and suddenly Android development has a clear structure — and you'll know exactly where to look when something breaks.

What You'll Learn

  • What each of the five core Android application components does and when to use it
  • How the Activity lifecycle controls what users see and when
  • How Services run background work without a UI, and how Broadcast Receivers react to system-wide events
  • How Content Providers share structured data between apps via the ContentResolver
  • How Intents — both explicit and implicit — wire all the components together

The Analogy

Think of an Android app as a busy city department. The Activity is the front desk — it's the face citizens interact with, open for business during the day. The Service is the back-office staff running overnight batch processes that citizens never see. Broadcast Receivers are the city's emergency alert system — when the siren sounds (say, "boot completed"), every registered listener wakes up and responds. The Content Provider is the central records office: other departments may request access to files, but only through the official window (the ContentResolver), with proper permissions. And Intents are the memos that travel between departments, either addressed to a specific office (explicit) or posted on the general board for whoever can handle it (implicit).

Chapter 1: Activities

Overview

An Activity represents a single screen with a user interface. Activities are the entry points for interacting with the user and are essential for any Android application. Each activity can contain multiple fragments and handle user interactions.

Key Points

  • Activities have a lifecycle with methods: onCreate(), onStart(), onResume(), onPause(), onStop(), and onDestroy().
  • Activities can start other activities using Intents.
  • The main activity is specified in the AndroidManifest.xml file.

Lifecycle Diagram

stateDiagram-v2
    [*] --> onCreate
    onCreate --> onStart
    onStart --> onResume
    onResume --> onPause : user navigates away
    onPause --> onResume : user returns
    onPause --> onStop
    onStop --> onRestart : user returns
    onRestart --> onStart
    onStop --> onDestroy
    onDestroy --> [*]

Example

MainActivity.java

package com.example.myapp;

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(v -> {
            // Handle button click
        });
    }
}

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="Click Me" />

</LinearLayout>

Chapter 2: Services

Overview

A Service is a component that performs long-running operations in the background. Services do not provide a user interface — they can be started and stopped by activities or other components, running silently behind the scenes.

Key Points

  • Services can run in the background even if the user switches to another application.
  • Started services perform a single operation (e.g., downloading a file) then stop themselves.
  • Bound services provide a client-server interface, allowing components to interact with them while they run.

Example

MyService.java

package com.example.myapp;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service {

    private static final String TAG = "MyService";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "Service Created");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "Service Started");
        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                Log.d(TAG, "Running task " + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            stopSelf();
        }).start();
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "Service Destroyed");
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

Register the service in AndroidManifest.xml:

<service android:name=".MyService" />

START_STICKY tells the OS to restart the service automatically if it is killed while running — important for long-lived background work.

Chapter 3: Broadcast Receivers

Overview

A Broadcast Receiver is a component that responds to system-wide broadcast announcements. It can listen for specific system events (like device boot or network changes) or custom broadcasts sent by your own app or third-party apps.

Key Points

  • Broadcast Receivers do not display a user interface.
  • They can be registered statically in AndroidManifest.xml (active even when the app is not running) or dynamically at runtime via registerReceiver().
  • They handle broadcasts from the system or other applications.

Example

MyBroadcastReceiver.java

package com.example.myapp;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class MyBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "Broadcast Received!", Toast.LENGTH_LONG).show();
    }
}

Register it statically in AndroidManifest.xml to fire on device boot:

<receiver android:name=".MyBroadcastReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

Chapter 4: Content Providers

Overview

A Content Provider manages access to a structured set of data. It encapsulates the data and provides mechanisms for defining data security. Content Providers are used to share data between applications — for example, the Android Contacts app exposes its data through a Content Provider that any app with permission can query.

Key Points

  • Content Providers provide a standard interface to access data via URIs.
  • They can read and write data stored in databases, files, or other storage mechanisms.
  • Data access and modification happens through the ContentResolver.
  • URI matching (UriMatcher) maps incoming URI patterns to the correct query logic.

Example

MyContentProvider.java — a full SQLite-backed provider:

package com.example.myapp;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class MyContentProvider extends ContentProvider {

    public static final String AUTHORITY = "com.example.myapp.provider";
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/items");

    private static final int ITEMS = 100;
    private static final int ITEM_ID = 101;

    private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    static {
        uriMatcher.addURI(AUTHORITY, "items", ITEMS);
        uriMatcher.addURI(AUTHORITY, "items/#", ITEM_ID);
    }

    private MyDatabaseHelper dbHelper;

    @Override
    public boolean onCreate() {
        dbHelper = new MyDatabaseHelper(getContext());
        return true;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
                        @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        SQLiteDatabase database = dbHelper.getReadableDatabase();
        Cursor cursor;
        switch (uriMatcher.match(uri)) {
            case ITEMS:
                cursor = database.query("items", projection, selection, selectionArgs,
                        null, null, sortOrder);
                break;
            case ITEM_ID:
                selection = "_id=?";
                selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
                cursor = database.query("items", projection, selection, selectionArgs,
                        null, null, sortOrder);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        cursor.setNotificationUri(getContext().getContentResolver(), uri);
        return cursor;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        switch (uriMatcher.match(uri)) {
            case ITEMS:
                return "vnd.android.cursor.dir/" + AUTHORITY + ".items";
            case ITEM_ID:
                return "vnd.android.cursor.item/" + AUTHORITY + ".items";
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        SQLiteDatabase database = dbHelper.getWritableDatabase();
        long id = database.insert("items", null, values);
        if (id > 0) {
            Uri returnUri = ContentUris.withAppendedId(CONTENT_URI, id);
            getContext().getContentResolver().notifyChange(uri, null);
            return returnUri;
        } else {
            throw new SQLException("Failed to insert row into " + uri);
        }
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection,
                      @Nullable String[] selectionArgs) {
        SQLiteDatabase database = dbHelper.getWritableDatabase();
        int rowsDeleted;
        switch (uriMatcher.match(uri)) {
            case ITEMS:
                rowsDeleted = database.delete("items", selection, selectionArgs);
                break;
            case ITEM_ID:
                selection = "_id=?";
                selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
                rowsDeleted = database.delete("items", selection, selectionArgs);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        if (rowsDeleted != 0) {
            getContext().getContentResolver().notifyChange(uri, null);
        }
        return rowsDeleted;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values,
                      @Nullable String selection, @Nullable String[] selectionArgs) {
        SQLiteDatabase database = dbHelper.getWritableDatabase();
        int rowsUpdated;
        switch (uriMatcher.match(uri)) {
            case ITEMS:
                rowsUpdated = database.update("items", values, selection, selectionArgs);
                break;
            case ITEM_ID:
                selection = "_id=?";
                selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
                rowsUpdated = database.update("items", values, selection, selectionArgs);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        if (rowsUpdated != 0) {
            getContext().getContentResolver().notifyChange(uri, null);
        }
        return rowsUpdated;
    }

    private static class MyDatabaseHelper extends SQLiteOpenHelper {

        private static final String DATABASE_NAME = "mydatabase.db";
        private static final int DATABASE_VERSION = 1;

        MyDatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            final String CREATE_TABLE = "CREATE TABLE items (" +
                    "_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
                    "name TEXT NOT NULL);";
            db.execSQL(CREATE_TABLE);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            db.execSQL("DROP TABLE IF EXISTS items");
            onCreate(db);
        }
    }
}

Register the provider in AndroidManifest.xml:

<provider
    android:name=".MyContentProvider"
    android:authorities="com.example.myapp.provider"
    android:exported="true"
    android:grantUriPermissions="true" />

android:exported="true" is required to allow other apps to access your provider. android:grantUriPermissions="true" lets your app grant temporary access to specific URIs to other apps on a per-request basis.

Chapter 5: Intents — the Messenger Between Components

Overview

Intents are messaging objects used to request actions from other app components. An Intent can start an Activity, start a Service, or deliver a broadcast. They are the glue that holds all the other four components together.

Key Points

  • Explicit Intents: Directly specify the component to start by class name. Used when you know exactly which component should handle the request (within your own app).
  • Implicit Intents: Do not specify a component. Instead, they declare a general action to perform, and the Android system finds the right component (in your app or another) that can handle it.

Example: Starting an Activity with an Explicit Intent

MainActivity.java — sends the user to SecondActivity on button press:

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(v -> {
            Intent intent = new Intent(MainActivity.this, SecondActivity.class);
            startActivity(intent);
        });
    }
}

SecondActivity.java — the destination screen:

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);
    }
}

Component Communication Map

flowchart LR
    A[Activity] -- Explicit Intent --> B[Activity]
    A -- startService Intent --> C[Service]
    A -- sendBroadcast Intent --> D[BroadcastReceiver]
    A -- ContentResolver --> E[ContentProvider]
    C -- sendBroadcast --> D
    D -- startActivity --> A

🧪 Try It Yourself

Task: Add a second screen to a basic Android project using an explicit Intent.

  1. In Android Studio, open (or create) a project with a MainActivity.
  2. Create a new empty Activity called SecondActivity (File → New → Activity → Empty Activity).
  3. In activity_main.xml, add a Button with android:id="@+id/btnGoToSecond" and text "Go to Second Screen".
  4. In MainActivity.java, wire the button to launch SecondActivity:
Button btnGoToSecond = findViewById(R.id.btnGoToSecond);
btnGoToSecond.setOnClickListener(v -> {
    Intent intent = new Intent(MainActivity.this, SecondActivity.class);
    startActivity(intent);
});
  1. In activity_second.xml, add a TextView with the text "Welcome to the Second Screen!".

Success criterion: Run the app. Tap the button — you should navigate to the second screen showing your welcome message. Press the back button to return to MainActivity.

🔍 Checkpoint Quiz

Q1. Which Activity lifecycle method is called first when an activity becomes visible to the user after being created?

A) onResume() B) onStart() C) onCreate() D) onRestart()

Q2. Given this service definition, what value does onStartCommand return, and what does it mean?

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    // ... background work ...
    return START_STICKY;
}

A) START_STICKY means the service will never restart after being killed. B) START_STICKY means the OS will restart the service after it is killed, but will not re-deliver the original intent. C) START_STICKY means the service stops itself after completing the task. D) START_STICKY means the service runs only while an activity is bound to it.

Q3. A developer registers a BroadcastReceiver in AndroidManifest.xml with the action android.intent.action.BOOT_COMPLETED. When exactly does the onReceive() method get called?

A) Every time the user opens the app B) When the device finishes booting C) When the app's main activity is destroyed D) When the user connects to Wi-Fi

Q4. You are building a notes app and want to expose your notes database so that a widget on the home screen (a separate process) can read the latest note. Which Android component is the correct tool, and what class does the widget use to talk to it?

Open-ended — write your answer before checking.

A1. B) onStart()onCreate() runs first internally, but onStart() is the call that marks the activity as visible. onResume() comes after, indicating the activity is in the foreground and interactive.

A2. B) START_STICKY tells the Android OS to restart the service after it is killed due to memory pressure. The OS will call onStartCommand() again, but the Intent parameter will be null because the original intent is not re-delivered. Use START_REDELIVER_INTENT if you need the original intent back.

A3. B) onReceive() is triggered when the device finishes booting and the system sends the BOOT_COMPLETED broadcast. This is commonly used to restart background services or schedule alarms after a reboot.

A4. The correct component is a Content Provider (MyContentProvider extends ContentProvider). The widget (running in a separate process) uses the ContentResolver — retrieved via getContext().getContentResolver() — to query the provider's URI (e.g., content://com.example.notesapp.provider/notes). The provider handles all SQLite access and returns a Cursor with the data.

🪞 Recap

  • An Activity is a single UI screen; its lifecycle (onCreateonDestroy) controls what is shown and when.
  • A Service runs background tasks with no UI; returning START_STICKY from onStartCommand keeps it alive through system restarts.
  • A Broadcast Receiver listens for system-wide or custom events, registered either statically in the manifest or dynamically at runtime.
  • A Content Provider exposes structured data (typically SQLite) to other apps or processes via a standardized URI interface and the ContentResolver.
  • Intents are the messaging glue of Android — explicit intents target a specific component by class, implicit intents describe an action and let the system route them.

📚 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.