Android App Components — Activities, Services, Broadcast Receivers, Content Providers
Every Android application is built using four essential components that serve as the building blocks of the app. These components define how the app interacts with the user, runs background tasks, responds to system events, and shares data. Understanding these components is the foundation of Android development.
AndroidManifest.xml file. Without proper declaration, components won't work. This is one of the most common mistakes beginners make.
1. Overview of the Four Components
| Component | Purpose | Entry Point |
|---|---|---|
| Activity | User interface screen | Launcher icon or intent |
| Service | Background operations | StartService() or bindService() |
| Broadcast Receiver | Respond to system events | System broadcasts or sendBroadcast() |
| Content Provider | Share data between apps | ContentResolver queries |
2. Activity — The User Interface
An Activity is a single, focused screen that the user can interact with. It provides a window for drawing the UI and handling user interactions. Almost every screen in your app will be an Activity.
Activity Lifecycle
Activities have a well-defined lifecycle managed by the Android system. Understanding this lifecycle is critical to building robust apps.
│ Activity Launched │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ onCreate() → Called when Activity is first created │
│ → Initialize UI, bind data │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ onStart() → Activity becomes visible │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ onResume() → Activity is in the foreground │
│ → User can interact │
└─────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────┐
│ Activity is running (foreground) │
└─────────────────────────────────────────────────────────────┘
│
┌────────────┴────────────┐
│ │
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ onPause() │ │ onDestroy() │
│ → Activity partially │ │ → Activity is being │
│ visible │ │ destroyed │
│ → Save user data │ │ → Clean up resources │
└─────────────────────────┘ └─────────────────────────┘
│ │
▼ │
┌─────────────────────────┐ │
│ onStop() │ │
│ → Activity no longer │ │
│ visible │ │
└─────────────────────────┘ │
│ │
▼ │
┌─────────────────────────┐ │
│ onRestart() │ │
│ → Activity restarting │ │
│ after being stopped │ │
└─────────────────────────┘ │
│ │
└────────────┬────────────┘
▼
┌─────────────────────────────────────────────────────────────┐
│ Activity is destroyed │
└─────────────────────────────────────────────────────────────┘
Activity Lifecycle Methods
| Method | When Called | What to Do |
|---|---|---|
onCreate() | Activity first created | Initialize UI, set content view, bind data |
onStart() | Activity becomes visible | Prepare UI for user interaction |
onResume() | Activity in foreground | Start animations, camera, GPS |
onPause() | Activity partially obscured | Save user data, stop animations |
onStop() | Activity no longer visible | Release resources, stop heavy operations |
onRestart() | Activity restarting after stop | Re-initialize resources |
onDestroy() | Activity being destroyed | Clean up all resources |
Basic Activity Implementation
// MainActivity.kt
package com.example.myapp
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Initialize UI elements
val button = findViewById<android.widget.Button>(R.id.myButton)
button.setOnClickListener {
Toast.makeText(this, "Button Clicked!", Toast.LENGTH_SHORT).show()
}
}
override fun onStart() {
super.onStart()
// Activity becomes visible
}
override fun onResume() {
super.onResume()
// Activity is in foreground
}
override fun onPause() {
super.onPause()
// Save user data here
}
override fun onStop() {
super.onStop()
// Release resources
}
override fun onDestroy() {
super.onDestroy()
// Final cleanup
}
}
3. Service — Background Operations
A Service is a component that runs in the background to perform long-running operations without a user interface. Services are ideal for tasks like playing music, downloading files, or fetching data from a server.
Types of Services
| Type | Description | Use Case |
|---|---|---|
| Started Service | Runs until stopped or destroyed | Downloading files, playing music |
| Bound Service | Allows client-server interaction | Music player (play/pause control) |
| Intent Service | Handles one-off tasks sequentially | Processing queue of requests |
| Foreground Service | Shows a notification | Music playback, navigation |
Basic Service Implementation
// MyService.kt
package com.example.myapp
import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.util.Log
class MyService : Service() {
companion object {
private const val TAG = "MyService"
}
override fun onCreate() {
super.onCreate()
Log.d(TAG, "Service created")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d(TAG, "Service started")
// Do background work here
Thread {
// Simulate long-running task
Thread.sleep(5000)
Log.d(TAG, "Background task completed")
stopSelf() // Stop the service when done
}.start()
return START_STICKY // Restart if killed by system
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "Service destroyed")
}
override fun onBind(intent: Intent?): IBinder? {
// Return null for started services
return null
}
}
Starting and Stopping a Service
// In your Activity or Fragment
val intent = Intent(this, MyService::class.java)
// Start the service
startService(intent)
// Stop the service
stopService(intent)
4. Broadcast Receiver — Responding to System Events
A Broadcast Receiver is a component that responds to system-wide broadcast announcements. It can listen to events like battery low, screen off, device boot, or custom broadcasts from your app.
Common System Broadcasts
| Action | Description |
|---|---|
android.intent.action.BOOT_COMPLETED | Device boot completed |
android.intent.action.BATTERY_LOW | Battery is low |
android.intent.action.AIRPLANE_MODE | Airplane mode toggled |
android.net.conn.CONNECTIVITY_CHANGE | Network connectivity changed |
android.intent.action.SCREEN_OFF | Screen turned off |
Broadcast Receiver Implementation
// BatteryBroadcastReceiver.kt
package com.example.myapp
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.widget.Toast
class BatteryBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
if (Intent.ACTION_BATTERY_LOW == action) {
Toast.makeText(context, "Battery is low!", Toast.LENGTH_LONG).show()
}
}
}
Registering a Broadcast Receiver
// Method 1: Register in AndroidManifest.xml (manifest-declared)
// <receiver android:name=".BatteryBroadcastReceiver">
// <intent-filter>
// <action android:name="android.intent.action.BATTERY_LOW" />
// </intent-filter>
// </receiver>
// Method 2: Register dynamically (recommended for newer Android versions)
class MainActivity : AppCompatActivity() {
private val batteryReceiver = BatteryBroadcastReceiver()
override fun onResume() {
super.onResume()
val filter = IntentFilter(Intent.ACTION_BATTERY_LOW)
registerReceiver(batteryReceiver, filter)
}
override fun onPause() {
super.onPause()
unregisterReceiver(batteryReceiver)
}
}
Sending Custom Broadcasts
// Send a custom broadcast
val intent = Intent("com.example.CUSTOM_EVENT")
intent.putExtra("message", "Hello from your app!")
sendBroadcast(intent)
// Receive custom broadcast
class CustomReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val message = intent.getStringExtra("message")
Toast.makeText(context, "Received: $message", Toast.LENGTH_SHORT).show()
}
}
5. Content Provider — Sharing Data
A Content Provider manages access to a structured set of data. It provides a standardized interface for sharing data between different applications. Content Providers are the only way to share data across apps securely.
Common Use Cases
- Contacts Provider: Access device contacts
- Media Store: Access photos, videos, and audio
- Calendar Provider: Access calendar events
- Files Provider: Share files with other apps
Using a Content Provider (Accessing Contacts)
// Access device contacts
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
readContacts()
}
private fun readContacts() {
val projection = arrayOf(
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME
)
val cursor = contentResolver.query(
ContactsContract.Contacts.CONTENT_URI,
projection,
null,
null,
null
)
cursor?.use {
while (it.moveToNext()) {
val name = it.getString(it.getColumnIndexOrThrow(
ContactsContract.Contacts.DISPLAY_NAME
))
Log.d("Contacts", "Name: $name")
}
}
}
}
Creating a Custom Content Provider
// MyContentProvider.kt
package com.example.myapp
import android.content.ContentProvider
import android.content.ContentValues
import android.database.Cursor
import android.net.Uri
class MyContentProvider : ContentProvider() {
companion object {
const val AUTHORITY = "com.example.myapp.provider"
val CONTENT_URI = Uri.parse("content://$AUTHORITY/data")
}
override fun onCreate(): Boolean {
// Initialize data source
return true
}
override fun query(
uri: Uri,
projection: Array<String>?,
selection: String?,
selectionArgs: Array<String>?,
sortOrder: String?
): Cursor? {
// Return data based on URI
// Called by other apps using ContentResolver
return null
}
override fun insert(uri: Uri, values: ContentValues?): Uri? {
// Insert data
return null
}
override fun update(
uri: Uri,
values: ContentValues?,
selection: String?,
selectionArgs: Array<String>?
): Int {
// Update data
return 0
}
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
// Delete data
return 0
}
override fun getType(uri: Uri): String? {
// Return MIME type
return "vnd.android.cursor.dir/vnd.com.example.data"
}
}
Declaring Content Provider in Manifest
<provider
android:name=".MyContentProvider"
android:authorities="com.example.myapp.provider"
android:exported="true" />
6. Component Lifecycle Summary
| Component | Lifecycle Methods | Key Points |
|---|---|---|
| Activity | onCreate, onStart, onResume, onPause, onStop, onDestroy | Has UI, interacts with user |
| Service | onCreate, onStartCommand, onBind, onDestroy | No UI, runs in background |
| Broadcast Receiver | onReceive | Short-lived, responds to events |
| Content Provider | onCreate, query, insert, update, delete | Manages shared data |
7. Production-Ready Checklist
- ✅ Declare all components — Every component must be declared in
AndroidManifest.xml. - ✅ Understand Activity lifecycle — Save and restore state in
onSaveInstanceState(). - ✅ Use Services wisely — Use WorkManager for background tasks on Android 8.0+.
- ✅ Register receivers properly — Use dynamic registration for modern apps.
- ✅ Handle permissions — Check and request permissions before accessing Content Providers.
- ✅ Avoid memory leaks — Unregister receivers and unbind services in lifecycle callbacks.
- ✅ Use foreground services — Show a notification for long-running services.
- ✅ Test configuration changes — Handle screen rotation and other configuration changes.
Ready to master Android Development?
Build real-world Android apps with hands-on projects, mentor-led sessions, and placement support.
.png)