Services & BroadcastReceivers

Run background work and respond to system-wide events

Started Service Bound Service Foreground Broadcasts

Table of Contents

Services Overview

A Service is an Android component that runs operations in the background without a UI. BroadcastReceivers listen for system-wide or app-specific events and react to them.

Activity (UI) → User-facing screens Service (no UI) → Long-running / background tasks BroadcastReceiver → React to events (boot, battery, network) WorkManager (modern) → Deferrable background work (next lesson)
ComponentPurposeHas UI
Started ServiceRun task until completeNo
Bound ServiceClient-server IPC with ActivityNo
Foreground ServiceVisible ongoing task (music, GPS)Notification only
BroadcastReceiverHandle broadcast IntentsNo

1Foreground Services

A foreground service performs work the user is actively aware of — music playback, fitness tracking, file download. It must show a persistent notification and is less likely to be killed by the system.

Manifest declaration (Android 14+)

XML — AndroidManifest.xml<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <application> <service android:name=".MusicPlaybackService" android:exported="false" android:foregroundServiceType="mediaPlayback" /> </application>

Foreground service implementation

Kotlin — MusicPlaybackService.ktclass MusicPlaybackService : Service() { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { val notification = createNotification("Playing: Learn Android") startForeground(NOTIFICATION_ID, notification) // Start playback work on background thread / coroutine playMusic() return START_STICKY } private fun createNotification(title: String): Notification { val channelId = "music_channel" if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( channelId, "Music Playback", NotificationManager.IMPORTANCE_LOW ) getSystemService(NotificationManager::class.java).createNotificationChannel(channel) } return NotificationCompat.Builder(this, channelId) .setContentTitle(title) .setContentText("Tap to return to app") .setSmallIcon(R.drawable.ic_music) .setOngoing(true) .build() } override fun onBind(intent: Intent?): IBinder? = null companion object { const val NOTIFICATION_ID = 1001 } }

Start foreground service from Activity

Kotlin — Start with ContextCompatval intent = Intent(this, MusicPlaybackService::class.java) ContextCompat.startForegroundService(this, intent)

Common foregroundServiceType values

TypeUse Case
mediaPlaybackMusic, podcast, video playback
locationGPS tracking, navigation
dataSyncUpload/download sync
cameraVideo recording in background
microphoneVoice call, recording

2Background Services

Background services run without user interaction. Modern Android heavily restricts them to save battery — most deferrable work should use WorkManager instead.

Android 8+ restriction: Background services cannot run freely when the app is in the background. Use foreground services for ongoing tasks, WorkManager for deferrable jobs, and coroutines for in-app async work.

Background restrictions summary

Android VersionRestrictionAlternative
8.0 (Oreo)Background service limitsForeground service or JobScheduler
9.0 (Pie)Foreground service requires permissionDeclare foregroundServiceType
12+Cannot start foreground service from backgroundExact alarm or user-visible action
14+Foreground service types enforcedMatch type to actual work

When to use what

User-visible ongoing task → Foreground Service Deferrable background work → WorkManager Short task while app is open → Coroutine / Thread in Activity Immediate system event → BroadcastReceiver (registered in code) Music stops when app killed → Don't use plain background Service

3Started Service

A started service is triggered with startService() or startForegroundService(). It runs until it stops itself or is stopped by the client. It does not return results to the caller directly.

Basic started service

Kotlin — DownloadService.ktclass DownloadService : Service() { private val serviceScope = CoroutineScope(Dispatchers.IO + SupervisorJob()) override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { val url = intent?.getStringExtra("download_url") ?: return START_NOT_STICKY serviceScope.launch { try { downloadFile(url) Log.d("DownloadService", "Download complete") } catch (e: Exception) { Log.e("DownloadService", "Download failed", e) } finally { stopSelf(startId) } } return START_NOT_STICKY } override fun onDestroy() { super.onDestroy() serviceScope.cancel() } override fun onBind(intent: Intent?): IBinder? = null }

Start and stop from Activity

Kotlin — Start DownloadService// Start val intent = Intent(this, DownloadService::class.java).apply { putExtra("download_url", "https://example.com/file.pdf") } startService(intent) // Stop stopService(Intent(this, DownloadService::class.java))

onStartCommand return values

Return ValueBehavior
START_STICKYSystem restarts service after kill; Intent is null
START_NOT_STICKYSystem does not restart after kill
START_REDELIVER_INTENTRestarts with last Intent redelivered

4Bound Service

A bound service offers a client-server interface. Components bind to it with bindService(), call methods through a Binder, and unbind when done. The service is destroyed when no clients are bound.

Local bound service with Binder

Kotlin — TimerService.ktclass TimerService : Service() { private val binder = TimerBinder() private var seconds = 0 private var isRunning = false inner class TimerBinder : Binder() { fun getService(): TimerService = this@TimerService } fun startTimer() { isRunning = true // Increment seconds in coroutine / handler } fun stopTimer() { isRunning = false } fun getElapsedSeconds(): Int = seconds override fun onBind(intent: Intent?): IBinder = binder }

Bind from Activity with ServiceConnection

Kotlin — MainActivity.ktclass MainActivity : AppCompatActivity() { private var timerService: TimerService? = null private var isBound = false private val connection = object : ServiceConnection { override fun onServiceConnected(name: ComponentName?, service: IBinder?) { val binder = service as TimerService.TimerBinder timerService = binder.getService() isBound = true } override fun onServiceDisconnected(name: ComponentName?) { timerService = null isBound = false } } override fun onStart() { super.onStart() Intent(this, TimerService::class.java).also { intent -> bindService(intent, connection, Context.BIND_AUTO_CREATE) } } override fun onStop() { super.onStop() if (isBound) { unbindService(connection) isBound = false } } fun onStartTimerClick() { timerService?.startTimer() } }

Started + Bound combined

Kotlin — Service can be both// Started: startForegroundService() keeps it alive // Bound: bindService() lets Activity call methods // Unbind does NOT stop a started service — call stopSelf() explicitly

5BroadcastReceiver Basics

A BroadcastReceiver receives and handles broadcast Intent objects. Use them to respond to system events or send messages between app components.

Two registration types

TypeRegistrationLifetime
Static (Manifest)Declared in AndroidManifest.xmlAlways active (limited actions on Android 8+)
Dynamic (Context)registerReceiver() in codeActive while registered; must unregister

Dynamic receiver in Activity

Kotlin — Register in Activityclass MainActivity : AppCompatActivity() { private val batteryReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { val level = intent?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: -1 val scale = intent?.getIntExtra(BatteryManager.EXTRA_SCALE, -1) ?: -1 val percent = (level * 100 / scale.toFloat()).toInt() binding.tvBattery.text = "Battery: $percent%" } } override fun onResume() { super.onResume() val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED) registerReceiver(batteryReceiver, filter) } override fun onPause() { unregisterReceiver(batteryReceiver) super.onPause() } }

Send custom broadcast

Kotlin — App-local broadcast// Send val intent = Intent("com.example.app.ACTION_TASK_COMPLETE").apply { putExtra("task_id", 42) putExtra("result", "success") } sendBroadcast(intent) // Receive (register with same action string) private val taskReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { val taskId = intent?.getIntExtra("task_id", -1) Toast.makeText(context, "Task $taskId done!", Toast.LENGTH_SHORT).show() } }

Manifest-declared receiver

XML — Static receiver (boot completed)<receiver android:name=".BootReceiver" android:exported="true" android:enabled="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

6System Broadcasts

System broadcasts are sent by Android when device state changes — network connectivity, battery level, screen on/off, boot completed. Most require dynamic registration on Android 8+.

Common system broadcast actions

Action ConstantTriggered When
ACTION_BOOT_COMPLETEDDevice finishes booting
ACTION_BATTERY_CHANGEDBattery level or status changes
ACTION_POWER_CONNECTEDCharger plugged in
ACTION_POWER_DISCONNECTEDCharger unplugged
CONNECTIVITY_ACTIONNetwork connectivity changes
ACTION_SCREEN_ON / OFFScreen turns on or off
ACTION_AIRPLANE_MODE_CHANGEDAirplane mode toggled
ACTION_LOCALE_CHANGEDSystem language changed

Network connectivity receiver

Kotlin — Network change listenerclass NetworkReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { val cm = context?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val network = cm.activeNetwork val capabilities = cm.getNetworkCapabilities(network) val isConnected = capabilities?.hasCapability( NetworkCapabilities.NET_CAPABILITY_INTERNET ) == true if (isConnected) { Log.d("Network", "Back online — sync pending data") } else { Log.d("Network", "Offline — queue requests") } } } // Register dynamically registerReceiver(NetworkReceiver(), IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))

BootReceiver example

Kotlin — BootReceiver.ktclass BootReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent?) { if (intent?.action == Intent.ACTION_BOOT_COMPLETED) { // Reschedule alarms, start sync, etc. Log.d("BootReceiver", "Device booted — rescheduling tasks") // Prefer WorkManager.enqueue() over starting services directly } } }

Modern best practice: For network, battery, and connectivity changes, prefer ConnectivityManager.NetworkCallback, WorkManager constraints, and BroadcastReceiver only when necessary. Keep onReceive() short — offload heavy work to a Service or WorkManager.

7Hands-On Exercises

1

Create a started service that simulates a file download with a 5-second delay, logs progress, then calls stopSelf().

2

Convert the download service to a foreground service with a progress notification. Update the notification as download progresses.

3

Build a bound service that tracks elapsed seconds. Bind from an Activity and display the timer in a TextView.

4

Register a dynamic BroadcastReceiver for ACTION_BATTERY_CHANGED and show battery percentage in the UI.

5

Send a custom app broadcast when a background task completes. Update a TextView in another Activity when received.

6

Create a manifest-declared BootReceiver that logs a message on device boot (test on emulator with cold boot).

7

Bonus: Listen for network connectivity changes and show a Snackbar when the device goes offline or comes back online.

Services & BroadcastReceivers MCQ Practice

10 Basic MCQs 10 Advanced MCQs

10 Basic Services & BroadcastReceivers MCQs

1

Service runs?

AOnly layouts
BBackground work without UI
COnly notifications UI
DGradle builds
Explanation: Long-running or heavy tasks outside Activity lifecycle.
2

Foreground Service shows?

AOnly toast
BNothing visible
CPersistent notification
DApp drawer icon only
Explanation: Required visible notification so user knows work continues.
3

Started Service begun with?

AsendBroadcast only
BbindService only
CstartActivity
DstartService(intent)
Explanation: Service runs until stopSelf or stopService.
4

Bound Service communicates via?

AIBinder interface
BSharedPreferences only
CLayout XML
DRoom DAO
Explanation: Client binds and calls methods on service binder.
5

BroadcastReceiver receives?

ASQL queries
BSystem or app-wide broadcast Intents
CTouch events only
DGradle sync
Explanation: Responds to events like BOOT_COMPLETED, CONNECTIVITY_CHANGE.
6

IntentService (deprecated) ran work on?

AGPU
BMain thread only
CBackground worker thread
DBinder only
Explanation: Replaced by WorkManager and coroutines for most cases.
7

stopSelf() in Service?

AClears database
BKills entire OS
CUninstalls app
DStops started service if no pending starts
Explanation: Used when background job completes.
8

LocalBroadcastManager?

ADeprecated — use LiveData/Flow/EventBus patterns in-app
BRequired for all apps
CReplaces Firebase
DSystem only
Explanation: For in-app events prefer ViewModel/Flow over implicit local broadcasts.
9

BOOT_COMPLETED receiver needs?

ACamera permission
BRECEIVE_BOOT_COMPLETED permission in manifest
CInternet only
DNo declaration
Explanation: Manifest permission plus intent-filter for ACTION_BOOT_COMPLETED.
10

Service declared in?

AGradle only
Bstrings.xml
CAndroidManifest.xml
Dlayout XML
Explanation: All Service subclasses must be registered.

10 Advanced Services & BroadcastReceivers MCQs

11

Android 8+ background Service limits?

ANo limits
BBackground start restricted — use foreground or WorkManager
CServices banned
DOnly bound allowed always
Explanation: startForegroundService + promote within timeout for visible work.
12

WorkManager vs Service?

AWorkManager replaces all Services always
BIdentical
CWorkManager for deferrable guaranteed work; Service for user-visible immediate
DService for SQL only
Explanation: Choose based on urgency, constraints, and user visibility.
13

Sticky broadcast?

ASame as ordered
BDefault for all apps
CRequired for GPS
DRemoved — security risk
Explanation: Sticky broadcasts deprecated; use other state mechanisms.
14

Ordered broadcast?

AReceivers run sequentially; abortBroadcast stops chain
BAll parallel always
CIllegal
DUI only
Explanation: sendOrderedBroadcast — priority receivers first.
15

Foreground service types (Android 14+)?

AOptional always
BDeclare type like location, mediaPlayback in manifest
CBanned
DAutomatic detection
Explanation: foregroundServiceType attribute required for specific use cases.
16

bindService flags BIND_AUTO_CREATE?

ARequires root
BDeletes service
CCreates service if not running when binding
DUI only
Explanation: Auto-create on bind; unbind may destroy if not started.
17

Exported receiver security?

AGradle controls
BAlways exported
CNo manifest entry
DSet exported=false unless external apps must send
Explanation: Android 12+ requires explicit android:exported for receivers.
18

JobIntentService?

ADeprecated — use WorkManager
BPreferred on Android 14
CReplaces Activity
DCamera API
Explanation: JobIntentService bridged to JobScheduler — now use WorkManager.
19

Service onStartCommand return START_STICKY?

ANever restart
BSystem restarts service after kill with null intent
CCrash app
DBind only
Explanation: START_NOT_STICKY, REDELIVER_INTENT are alternatives.
20

Implicit broadcast restrictions (8+)?

ANo restrictions
BAll broadcasts allowed at runtime
CMany implicit broadcasts only via manifest at register time limited
DFirebase only
Explanation: Most implicit broadcasts restricted — use explicit or JobScheduler/WorkManager.
Click an option to select, then check answers.

Services & BroadcastReceivers Interview Q&A

15 topic-focused questions for interviews and revision.

1Difference started vs bound Service.medium
Answer: Started: runs independently via startService. Bound: client-server connection via bindService until unbound.
2When to use Foreground Service?easy
Answer: User-visible ongoing work: music playback, navigation, fitness tracking — must show notification.
3How to start foreground service.medium
Answer: startForegroundService(intent); in onStartCommand call startForeground(id, notification) within time limit.
4What is BroadcastReceiver?easy
Answer: Component receiving Intent broadcasts — system events or app-sent broadcasts.
5Register receiver dynamically.medium
Answer: context.registerReceiver(receiver, IntentFilter(ACTION)) — unregister in onPause/onDestroy.
6Why restrict background Services?medium
Answer: Battery and resource abuse — Android limits background execution.
7WorkManager vs Foreground Service.medium
Answer: WorkManager: deferrable sync/upload with constraints. Foreground: user-aware immediate long task.
8BOOT_COMPLETED use case.medium
Answer: Schedule alarms, register listeners, enqueue WorkManager after device reboot — sparingly.
9Security for exported receivers.hard
Answer: Use custom permissions or explicit intents; validate action and data; set exported=false when internal.
10Service lifecycle callbacks.easy
Answer: onCreate, onStartCommand (started), onBind (bound), onDestroy.
11Communication Activity to Service.medium
Answer: startService with Intent extras, bound Service binder, or shared ViewModel/Repository singleton.
12Stop started Service.easy
Answer: service.stopSelf() or context.stopService(intent).
13Local events without BroadcastReceiver.medium
Answer: SharedFlow, LiveData single events, or callback interface — prefer over local broadcasts.
14Foreground service notification requirement.easy
Answer: Cannot be dismissed while running; channel required on Android 8+.
15Testing Services.hard
Answer: Robolectric or instrumented tests; mock dependencies; use WorkManager TestDriver for workers.