Services

A service is an application component that is designed to perform long-running operations in the background such as playing music.

A service doesn't has any UI. But service can be bounded by a component to perform interactivity and inter process communication.

A service runs in the main thread. You should run any blocking operations on a separate thread within the service to avoid Application Not Responding (ANR) errors.

The service can run in the background even after the application is destroyed.

started service

A started service service that is started from the startService() method of context. Such service lives until stopService() is called. Also service can stop self after finishing job by the stopSelf() method.

Started service template
class MyService : Service() {

    // prepare the service for work
    override fun onCreate() { /* ... */ }
 
    // handle a request
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {   
        // extract data from intent and do job
        // ...
        return START_STICKY
    }

    // not used, so return null
    override fun onBind(intent: Intent?): IBinder? {
        return null
    }

    override fun onDestroy() {/* */}
}

The onStartCommand method can return following values:

  • START_NOT_STICKY - if the system kills the service after onStartCommand() returns, do not recreate the service unless there are pending intents to deliver. This is the safest option to avoid running your service when not necessary and when your application can simply restart any unfinished jobs.
  • START_STICKY - if the system kills the service after onStartCommand() returns, recreate the service and call onStartCommand(), but do not redeliver the last intent. Instead, the system calls onStartCommand() with a null intent.
  • START_REDELIVER_INTENT - if the system kills the service after onStartCommand() returns, recreate the service and call onStartCommand() with the last intent that was delivered to the service.
Service example

bound service

A bound service is the server in a client-server interface. It allows components such as activities to bind to the service, send requests, receive responses, and perform interprocess communication (IPC). A bound service typically lives only while it serves another application component and does not run in the background indefinitely.

A client binds to a service by calling bindService() method of context. To unbind, use the unbindService() method.

If your service is used only by the local application and does not need to work across processes, then you can implement your own Binder class that provides your client direct access to public methods in the service.

Bound service template
class LocalService : Service() {
    // Binder given to clients
    private val binder = LocalBinder()

    // Random number generator
    private val mGenerator = Random()

    /** method for clients  */
    val randomNumber: Int
        get() = mGenerator.nextInt(100)

    /**
     * Class used for the client Binder.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    inner class LocalBinder : Binder() {
        // Return this instance of LocalService so clients can call public methods
        fun getService(): LocalService = this@LocalService
    }

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

If you need your service to communicate with remote processes, then you can use a Messenger to provide the interface for your service. If it's important that your service be multi-threaded, use AIDL (Android Interface Definition Language ) to define your interface.

Using a Messenger is simpler than using AIDL.

register service

To use service you need declare it in the AndroidManifest.xml file. The main properties are

  • name - a class name of service
  • description - description of service for user
  • exported - true means that any application can use the service, false means that the service is only available to your app
Code example
<manifest ... >
  ...
  <application ... >
      <service android:name=".MyService" 
       android:description="@string/my_service_description"
       android:exported="false"
      />
      ...
  </application>
</manifest>

foreground service

Each foreground service must show a status bar notification. That way, users are actively aware that your app is performing a task in the foreground and is consuming system resources. The notification cannot be dismissed unless the service is either stopped or removed from the foreground.

If notification has priority lower than PRIORITY_LOW, the system adds a message to the notification drawer, alerting the user to the app's use of a foreground service.

You should only use a foreground service when your app needs to perform a task that is noticeable by the user even when they're not directly interacting with the app. For example

  • a music player might show the current song that is being played
  • a fitness app might show the distance that the user has traveled during the current fitness session

From API 28 you must add permission to the AndroidManifest.xml.

Add permission example

To start foreground service you must provide notification.

Code example

To stop service use a stopForeground() method.