When to Use Foreground Services
The Problem with Background Work
Android aggressively restricts background execution to preserve battery life. Apps cannot run long-running operations in the background after the user leaves the app. A foreground service solves this by elevating the process priority and showing a persistent notification.
When a Foreground Service Is Required
Use a foreground service when the user must be aware the app is doing work and the work cannot be interrupted:
- Music playback — playing audio while the app is in the background
- GPS tracking — recording location during navigation or fitness tracking
- File downloads — large downloads that must complete without interruption
- Data synchronization — ongoing sync with a server
- Phone calls — VoIP apps maintaining a connection
When NOT to Use a Foreground Service
- Periodic data refresh — use WorkManager instead
- One-shot network calls — use coroutines with WorkManager
- Short processing — WorkManager or JobIntentService
Android Version Restrictions
| Version | Restriction |
|---|---|
| Android 8.0+ | Background service start限制. Must use startForeground() within 5 seconds |
| Android 12+ | Cannot start foreground services from background unless exempt |
| Android 14+ | TYPE_LOCATION and TYPE_MICROPHONE foreground service types require runtime permissions |
// Android 12+: Check if you can start a foreground service
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val am = getSystemService<ActivityManager>()
if (!am?.isForegroundServiceLaunchAllowed) {
// Show explanation or use WorkManager instead
return
}
}
Foreground Service vs WorkManager
| Feature | Foreground Service | WorkManager |
|---|---|---|
| User visibility | Persistent notification | No notification |
| Duration | Indefinite | Up to 10 minutes |
| Process priority | Foreground | Expedited worker |
| Use case | Music, GPS, calls | Sync, upload, cleanup |
Implementing Foreground Services
Service Declaration
Register the service in AndroidManifest.xml. For Android 9+, declare the foreground service type.
<service
android:name=".MusicService"
android:foregroundServiceType="mediaPlayback"
android:exported="false" />
Service Implementation
A foreground service must call startForeground() with a notification within 5 seconds of being started, or the system kills the process.
class MusicService : Service() {
private val binder = MusicBinder()
private var mediaPlayer: MediaPlayer? = null
inner class MusicBinder : Binder() {
fun getService(): MusicService = this@MusicService
}
override fun onBind(intent: Intent): IBinder = binder
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
when (intent?.action) {
ACTION_PLAY -> play(intent.getStringExtra(EXTRA_TRACK_URL))
ACTION_PAUSE -> pause()
ACTION_STOP -> stopSelf()
}
return START_STICKY // restart if killed by system
}
private fun play(url: String?) {
url?.let {
mediaPlayer = MediaPlayer().apply {
setDataSource(it)
prepare()
start()
}
startForeground(NOTIFICATION_ID, buildNotification("Playing"))
}
}
private fun pause() {
mediaPlayer?.pause()
updateNotification("Paused")
}
override fun onDestroy() {
mediaPlayer?.release()
mediaPlayer = null
super.onDestroy()
}
private fun buildNotification(text: String): Notification {
val intent = Intent(this, MainActivity::class.java)
val pending = PendingIntent.getActivity(
this, 0, intent, PendingIntent.FLAG_IMMUTABLE
)
return NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Music Player")
.setContentText(text)
.setSmallIcon(R.drawable.ic_music)
.setContentIntent(pending)
.build()
}
companion object {
const val NOTIFICATION_ID = 1
const val CHANNEL_ID = "music_channel"
const val ACTION_PLAY = "com.example.PLAY"
const val ACTION_PAUSE = "com.example.PAUSE"
const val ACTION_STOP = "com.example.STOP"
const val EXTRA_TRACK_URL = "track_url"
}
}
Starting the Service
// Start from an Activity or Fragment
val intent = Intent(this, MusicService::class.java).apply {
action = MusicService.ACTION_PLAY
putExtra(MusicService.EXTRA_TRACK_URL, trackUrl)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent)
} else {
startService(intent)
}
Service Lifecycle
- Created —
onCreate()called once when service is first created - Started —
onStartCommand()called each timestartService()is invoked - Bound —
onBind()called when a client binds viabindService() - Destroyed —
onDestroy()called when service is stopped
Notification Channels
Android 8.0+ requires a notification channel for foreground service notifications:
fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
CHANNEL_ID,
"Music Playback",
NotificationManager.IMPORTANCE_LOW
)
getSystemService(NotificationManager::class.java)
.createNotificationChannel(channel)
}
}
Use IMPORTANCE_LOW so the notification does not make sound or appear on the lock screen — it is just a persistent indicator.
Quiz
1. How long does an Android foreground service have to call startForeground() after being started?
2. Which foreground service type should a music player use on Android 14+?
3. What does `START_STICKY` return from `onStartCommand` do?
4. Why should you use IMPORTANCE_LOW for a foreground service notification channel?
Flashcards
Question
When must you use a foreground service instead of WorkManager?
Click to reveal answer
Answer
When the user must be aware of ongoing work (persistent notification required) and the work cannot be interrupted or time-boxed — such as music playback, GPS tracking, or VoIP calls.
Question
What happens if a foreground service does not call startForeground() within 5 seconds?
Click to reveal answer
Answer
The system kills the process with an ANR (Application Not Responding) error on Android 8.0+.
Question
What is the difference between startService() and bindService()?
Click to reveal answer
Answer
startService() sends a command to the service; it runs independently of the caller. bindService() creates a connection — the caller can interact with the service through a Binder, and the service stops when all clients unbind.
Question
How do you start a foreground service on Android 8.0+?
Click to reveal answer
Answer
Use startForegroundService(intent) instead of startService(). The service must call startForeground() with a notification within 5 seconds.
Revision Notes
Key Takeaways
- 1. Foreground services are for long-running, user-visible work that cannot be interrupted
- 2. startForeground() must be called within 5 seconds or the process is killed
- 3. Android 12+ restricts foreground service starts from the background — check exemptions
- 4. Use WorkManager for periodic or deferrable work instead of foreground services
Interview Tips
- • Explain the tradeoff: foreground services keep work alive but drain battery and show notifications
- • Know when to recommend WorkManager over foreground services — interviewers ask this
- • Mention Android version restrictions as a real-world concern
- • Be ready to explain service lifecycle (onStartCommand, onBind, onDestroy)
Cheat Sheet
Foreground Services Cheat Sheet
Use When:
- User must know about ongoing work
- Work must not be interrupted
- Duration is indefinite (music, GPS, calls)
Avoid When:
- Periodic background work → WorkManager
- Short network calls → Coroutines
Key Requirements:
- Call startForeground() within 5 seconds
- Show a persistent notification
- Declare foregroundServiceType in manifest
- Android 14+: Runtime permissions for location/mic types
Service Lifecycle:
- onCreate → onStartCommand → onDestroy
- onBind for bound services
- START_STICKY: restart after killed
Notification Channels:
- Create with IMPORTANCE_LOW
- No sound or lock screen — just an indicator
Android 12+ Restrictions:
- Cannot start from background unless exempt
- Use isForegroundServiceLaunchAllowed to check