Go back

Foreground Services in android

Published on 11 May, 2025

Foreground services let you asynchronously perform operations that are noticeable to the user. Foreground services show a status bar notification, to make users aware that your app is performing a task in the foreground and is consuming system resources.

Examples of apps that use foreground services include the following:

  1. A music player app that plays music in a foreground service. The notification might show the current song being played.
  2. A fitness app that records a user’s run in a foreground service, after receiving permission from the user. The notification might show the distance that the user has traveled during the current fitness session.

Creating a New Service

In this tutorial, we will create a fake demo fitness app service.

  1. Create a new file RunningService.kt. In this file add a class RunningService that extends from Service() class. Here we need one mandatory function onBind. Now to start a service we have onStartCommand() method that will take the intent.action and will start/stop the service. To stop service stopSelf() is a predefined method that is provided by the class. To start, we declare our own start() method.
class RunningService : Service() {
    override fun onBind(intent: Intent?): IBinder? {
        return null
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        when(intent?.action){
            Actions.START.toString() -> start()
            Actions.STOP.toString() -> stopSelf() // stop the service
        }
        return super.onStartCommand(intent, flags, startId)
    }

    private fun start(){
        // need to show notification
        // every service is also an context
        val notification = NotificationCompat.Builder(this, "running_channel" ).setSmallIcon(R.drawable.ic_launcher_foreground).setContentTitle("Run is active").setContentInfo("Elapsed time: 00: 50").build()
        startForeground(1, notification)
    }

    enum class Actions{
        START, STOP
    }
}
  1. Now in the AndroidMainfest.xml file, we first declare a few permisisons that will allow us to ask for Notification Permission and an less dangerous permission for Foreground Services.
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
  1. In same AndroidMainfest.xml file, now inside the <application>, we will define a service as well with a foregrounServiceType as dataSync.
<application>
  <service
      android:name=".RunningService"
      android:enabled="true"
      android:exported="false"
      android:foregroundServiceType="dataSync"
      />
</application>
  1. Now to request the permission for Notification, we need to create a channelId. In Step 1, we set that as running_channel. However, we need to create that as soon as our app launch. So we can do this in RunningApp which extends from Application(), so that this could would be automatically run when our app first boots up. This will create the notification channel, used to send our notification.
class RunningApp : Application() {
    override fun onCreate() {
        super.onCreate()
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            val channel = NotificationChannel(
                "running_channel", "Running Notifications", NotificationManager.IMPORTANCE_HIGH
            )

            val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(channel)

        }
    }
}
  1. Now we need Notification Permission from the user by showing the dialog. Since it’s a foreground service, showing notification is necessary. Now we need to request the permission from the user. So in MainActivity, we will request this permission.
// services -> REQ PERMISSION
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU){
        ActivityCompat.requestPermissions(
            this,
            arrayOf(Manifest.permission.POST_NOTIFICATIONS),0
        )
    }
  1. Now we can send the intent from MainActivity to RunningService with an intent to either start ot stop the service. To start a service we can launch it using startService() function on the intent.
Column {
  Text("Running Service")
  Button(
      onClick = {
          Intent(applicationContext, RunningService::class.java).also {
              it.action = RunningService.Actions.START.toString()
              startService(it)
          }
      }
  ) {
      Text(text = "Start Run")
  }
  Button(
      onClick = {
          Intent(applicationContext, RunningService::class.java).also {
              it.action = RunningService.Actions.STOP.toString()
              startService(it)
          }
      }
  ) {
    Text(text = "Stop Run")
  }}

So even if we close our app, you can see the notification would still be there.