12.1. Foreground services

As previously mentioned, foreground services can send notifications. This is the main difference with respect to other types of services.

In all the examples of services that we are going to perform the objective will be for the service to perform the playback of an audio .mp3 file

First, we define a class MyServiceForeground that inherits from Service.

class MyServiceForeground : Service() {

   protected lateinit var mediaPlayer: MediaPlayer

   companion object {
       fun startService(context: Context, message: String) {
           val startIntent = Intent(context, MyServiceForeground::class.java)
           startIntent.putExtra("inputExtra", message)
           ContextCompat.startForegroundService(context, startIntent)
       }
       fun stopService(context: Context) {
           val stopIntent = Intent(context, MyServiceForeground::class.java)
           context.stopService(stopIntent)
       }
   }

   override fun onBind(intent: Intent): IBinder? {
       return null
   }

   override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {

       val pendingIntent: PendingIntent =
           Intent(this, MainActivity::class.java).let { notificationIntent ->
               PendingIntent.getActivity(this, 0, notificationIntent, 0)
           }

       val notification: Notification = Notification.Builder(this, "alert_channel")
           .setContentTitle("Play new track")
           .setContentText("")
           .setSmallIcon(R.drawable.ic_launcher_foreground)
           .setContentIntent(pendingIntent)
           .setTicker("")
           .build()

       startForeground(1, notification)

       mediaPlayer = MediaPlayer.create(this, R.raw.sound1)
       mediaPlayer?.start()

       return START_NOT_STICKY
   }
}

In this class we define two static methods (companion object) startService and stopService that will allow us to create and stop instances of this service in the foreground.

In the manifest.xml file we must declare the service:

<service
   android:name=".MyServiceForeground"
   android:enabled="true"
   android:exported="true" />

We also indicate that we will need permission to run foreground services.

<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>

Now from the main activity we can create the service using the static method startService of our class MyServiceForeground:

MyServiceForeground.startService(this, "Foreground Service is running...")

Inside the static method startService, the service instance will be created. We can pass parameters to the service using the Intent. In this case we pass the message as a parameter.

       fun startService(context: Context, message: String) {
           val startIntent = Intent(context, MyServiceForeground::class.java)
           startIntent.putExtra("inputExtra", message)
           ContextCompat.startForegroundService(context, startIntent)
       }

As a result of running startForegroundService, the callback onStartCommand will be invoked. First, this call callback creates a notification to indicate that an audio file will start playing. The notification channels to be used must have been created earlier from the main activity.

The following code creates the notification:

val pendingIntent: PendingIntent =
   Intent(this, MainActivity::class.java).let { notificationIntent ->
       PendingIntent.getActivity(this, 0, notificationIntent, 0)
   }

val notification: Notification = Notification.Builder(this, "alert_channel")
   .setContentTitle("Play new track")
   .setContentText("")
   .setSmallIcon(R.drawable.ic_launcher_foreground)
   .setContentIntent(pendingIntent)
   .setTicker("")
   .build()

startForeground(1, notification)

Now we can add the code to start playing the audio file:

mediaPlayer = MediaPlayer.create(this, R.raw.sound1)
mediaPlayer?.start()

Since it is running on the same thread and process as the main activity, when we close the application the service is destroyed and playback is stopped.