Foreground Services allow long-running background tasks with visible notifications. Essential for music players, fitness trackers, and navigation apps.
Manifest Setup
Declare foreground service permissions:
<!-- AndroidManifest.xml -->
<manifest>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<application>
<service
android:name=".MusicService"
android:foregroundServiceType="mediaPlayback" />
</application>
</manifest>
Basic MusicService Implementation
Create a foreground service:
class MusicService : Service() {
private val binder = MusicBinder()
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val notification = createNotification()
startForeground(NOTIFICATION_ID, notification)
return START_STICKY
}
private fun createNotification(): Notification {
val channel = NotificationChannel(
CHANNEL_ID,
"Music Service",
NotificationManager.IMPORTANCE_LOW
)
(getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager)
.createNotificationChannel(channel)
return NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Now Playing")
.setContentText("Song name")
.setSmallIcon(R.drawable.ic_music)
.build()
}
inner class MusicBinder : Binder() {
fun getService(): MusicService = this@MusicService
}
override fun onBind(intent: Intent?): IBinder? = binder
}
Compose Control UI
Start and stop service from Compose:
@Composable
fun MusicControlScreen() {
val context = LocalContext.current
var isPlaying by remember { mutableStateOf(false) }
Column {
Button(
onClick = {
val intent = Intent(context, MusicService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent)
} else {
context.startService(intent)
}
isPlaying = true
}
) {
Text("Start Music")
}
Button(
onClick = {
val intent = Intent(context, MusicService::class.java)
context.stopService(intent)
isPlaying = false
}
) {
Text("Stop Music")
}
}
}
Permission Launcher
Request runtime permissions:
@Composable
fun PermissionRequest() {
val permissionLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
// Permission granted, start service
}
}
Button(
onClick = {
permissionLauncher.launch(Manifest.permission.FOREGROUND_SERVICE)
}
) {
Text("Request Permission")
}
}
Timer Service with Binder
Long-running background work:
class TimerService : Service() {
private var timeElapsed = 0
private var isRunning = false
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
startTimer()
return START_STICKY
}
private fun startTimer() {
isRunning = true
viewModelScope.launch {
while (isRunning) {
timeElapsed++
updateNotification()
delay(1000)
}
}
}
fun stopTimer() {
isRunning = false
}
inner class TimerBinder : Binder() {
fun getTimeElapsed(): Int = timeElapsed
}
}
Android 14+ Service Types
Specify foregroundServiceType for different use cases:
<!-- Camera service -->
<service
android:name=".CameraService"
android:foregroundServiceType="camera" />
<!-- Location tracking -->
<service
android:name=".LocationService"
android:foregroundServiceType="location" />
<!-- Health/fitness tracking -->
<service
android:name=".FitnessService"
android:foregroundServiceType="health" />
<!-- Short jobs (< 1 minute) -->
<service
android:name=".QuickService"
android:foregroundServiceType="shortService" />
Foreground Services power critical background features in production apps.
8 Android app templates available: Gumroad
Top comments (0)