Android Services: Getting Started

Learn about Android Services and the differences between foreground, background and bound services. By Gabriela Kordić.

Leave a rating/review
Download materials
Save for later
Share

Many Android apps have features that take a long time to run, like downloading content or updating a remote database. If developers don’t handle these features properly, they slowly clutter the main thread, creating memory leaks and inconsistencies in the results. This leads to a bad user experience.

Fortunately, there’s a solution for handling these actions: Android Services. This is a special type of application component that’s designed to handle repetitive and long running jobs.

In this tutorial, you’ll learn:

  • What Android Services are and how to declare them in the Manifest file.
  • How to use a foreground service while displaying a notification to the user.
  • What is it with background processing for complex work that isn’t related to the UI.
  • How to use a bound service.
Note: This tutorial assumes intermediate knowledge of Kotlin, Android and Android Studio. If you’re new to Android development or haven’t installed Android Studio, refer to our Beginning Android Development tutorials.

Getting Started

Download the starter project by using the Download Materials button at the top or bottom of this tutorial.

For this tutorial, you’ll use the Memo app. Memo is a game that challenges the user to match cards in the shortest possible time. Additionally, the user can listen to audio tracks while they play.

The game has four levels: Beginner, Intermediate, Advanced and Expert. The higher the level, the more cards to match. After the user finishes the expert level, they complete the game. Do you dare to try your luck? :]

Currently, the app only lets the user start a game and manipulate the audio tracks. Once you start a game, you’ll be able to quit, preview game cards and track the time elapsed since the game started.

Open the project in Android Studio and get familiar with the files. When you’re done, build and run it on a device/emulator to see how the app looks.

Memo's main screen

Play the game by pressing PLAY BEGINNER LEVEL. At this point, you can match the cards but there’s no timer to show how long it took you to win. That’s the first thing you’ll implement in this tutorial.

Beginner level of the Memo game

First, however, you’ll take a deeper look at Android Services.

Introducing Android Services

An Android Service is a component that helps execute long-running processes, like updating a database or server, running a countdown and playing audio. By default, Android Services run in the same process as the main application thread does. This kind of service is also known as a local service.

For resource-intensive tasks, the service executes the work on the background thread. This lets the user run actions without being disturbed. For example, if the user wants to make a call or check messages while updating a server, they can do so without interrupting or aborting the update action.

To do this, the developer needs to create a background thread and manually specify which tasks should run on it because the service doesn’t directly support the thread implementation.

Since an Android Service doesn’t have a user interface, it isn’t bound to the activity’s lifecycle. That means you can run it even when the user isn’t interacting with the app.

Additionally, other components can bind to the service and interact with it, or even do InterProcess Communication (IPC). You’ll learn more about IPC later in this tutorial.

In the following sections, you’ll implement each of the below types of Android Services in the Memo app to achieve the following features:

  • Foreground service: Add TimerService, which contains logic to track time.
  • Bound service: Implement MusicService, which will let you play, pause, stop and shuffle the audio tracks.

It’s time to get started!

Declaring a Service in the Manifest

Before using a service, you need to declare it in AndroidManifest.xml. After all, it’s an Android component, just like Activities are. For simplicity, the starter project already contains the Service classes, but you still need to configure them properly.

Navigate to AndroidManifest.xml and add this code inside application:

    <service
      android:name=".services.TimerService"
      android:enabled="true"
      android:exported="false" />

    <service
      android:name=".services.MusicService"
      android:enabled="true"
      android:exported="false" />

In this code, you see the following:

  • android:name: The name of the Service class.
  • android:enabled: When set to true allows the system to instantiate the services.
  • android:exported: When set to false tells the system that components of another application can’t start these services.

The value of android:name is in red, but just ignore that for now. You’ll fix this soon.

For now, you’ll start with the implementation.

Implementing the Service Interface

Every custom service class must be a subclass of Service and must implement and override a few basic callback methods connected to the service lifecycle.

The most important of these are:

  • onStartCommand(): Called by the system when another component wants to start a service using startService(). Once the system calls onStartCommand(), the service can run in the background for as long as it takes to complete. You need to remember to stop the service manually when the work is over by calling stopSelf() or stopService(). You don’t need this implementation if you only want to bind to the service without an option to start it.
  • onBind(): You always need to implement this callback method. The system invokes it when bindService() is called. Use it to bind another component to the service. It opens a communication, so you’ll provide an interface for the clients to communicate by returning IBinder. If you don’t want to use binding, just return null.
  • onCreate(): Use this method to set up a service before it starts. The system invokes it only if the service isn’t running yet.
  • onDestroy(): The system invoke this to destroy the service when it is not needed anymore. It’s the last call the service receives and it cleans up the resources or threads.

Creating a Foreground Service

A foreground service executes tasks that the user needs to see. It shows a status bar notification to alert the user that an app is performing an operation and consuming resources. The notification must have a priority of PRIORITY_LOW or higher and must be visible even when the user isn’t interacting with the app.

The user can’t dismiss the notification; it disappears when the service stops or leaves the foreground.

To see this in play, you’ll implement TimerService. Open TimerService.kt and add the following to make it a subclass of Service:

class TimerService : Service(), CoroutineScope {

With this code, you implement the Service and CoroutineScope interface.