The following is the first few sections of a chapter from The Busy Coder's Guide to Android Development, plus headings for the remaining major sections, to give you an idea about the content of the chapter.


Services and the Command Pattern

As noted previously, Android services are for long-running processes that may need to keep running even when decoupled from any activity. Examples include playing music even if the “player” activity is destroyed, polling the Internet for RSS/Atom feed updates, and maintaining an online chat connection even if the chat client loses focus due to an incoming phone call.

Services are created when manually started (via an API call) or when some activity tries connecting to the service via inter-process communication (IPC). Services will live until specifically shut down, until Android is desperate for RAM and terminates the process, or for a short period of time on Android 8.0+. Running for a long time has its costs, though, so services need to be careful not to use too much CPU or keep radios active too much of the time, lest the service cause the device’s battery to get used up too quickly.

This chapter outlines the basic theory behind creating and consuming services, including a look at the “command pattern” for services.

Why Services?

Services are a “Swiss Army knife” for a wide range of functions that do not require direct access to an activity’s user interface, such as:

  1. Performing operations that need to continue even if the user leaves the application’s activities, like a long download (as seen with the Play Store) or playing music (as seen with Android music apps)
  2. Performing operations that need to exist regardless of activities coming and going, such as maintaining a chat connection in support of a chat application
  3. Providing a local API to remote APIs, such as might be provided by a Web service
  4. Performing periodic work without user intervention, akin to cron jobs or Windows scheduled tasks

Even things like home screen app widgets often involve a service to assist with long-running work.

The primary role of a service is as a flag to the operating system, letting it know that your process is still doing work, despite the fact that it is in the background. This makes it somewhat less likely that Android will terminate your process due to low memory conditions.

Many applications will not need any services. Very few applications will need more than one. However, the service is a powerful tool for an Android developer’s toolbox and is a subject with which any qualified Android developer should be familiar.

Setting Up a Service

Creating a service implementation shares many characteristics with building an activity. You inherit from an Android-supplied base class, override some lifecycle methods, and hook the service into the system via the manifest.

The Service Class

There are many service classes that you might inherit from.

The root of all of them is Service, just as the root of the hierarchy of activity classes is Activity. You may wish to subclass Service, particularly if:

Historically, the next-most-common base class was IntentService. This was good for a “transactional” bit of work, where you need to have a service do something in the background for a bit, then you no longer need the service. The classic example here is a service to download a large file: once the file is downloaded, you no longer need that service to be around. IntentService supplies you with a background thread to use for the network I/O and disk I/O, and it will shut down automatically once the work is complete.

However, IntentService has recently been supplanted by JobIntentService. This has similar characteristics, but it works better on Android 8.0+ devices, due to limitations on what you can do in the background.

We will examine all three of these solutions in this chapter.

Beyond those, there are many specialized service classes. Elsewhere in the book you will find examples of:

And there are plenty of others. While they are all services, and they will all be added to the manifest in the same fashion (more or less), the API that you implement will be very specific to the service that you are extending. The API for TileService looks little like the API for JobService, for example. As such, those services, where we use them, are covered elsewhere in the book.

Lifecycle Methods

Just as activities have onCreate(), onResume(), onPause() and kin, Service implementations have their own lifecycle methods, such as:

As with activities, services initialize whatever they need in onCreate() and clean up those items in onDestroy(). And, as with activities, the onDestroy() method of a service might not be called, if Android terminates the entire application process, such as for emergency RAM reclamation.

The onStartCommand() and onBind() lifecycle methods will be implemented based on your choice of communicating to the client, as will be explained later in this chapter.

Note that Service is an abstract class and onBind() is an abstract method, so even if you are not using bindService(), you will need to implement onBind() in order to successfully compile. A common approach here is to have onBind() simply return null.

Note that these methods may be optional, depending upon your needs and the base class that you extend. So, for example, overriding any of these in a JobIntentService is unusual at best and a bad idea at worst.

Manifest Entry

Finally, you need to add the service to your AndroidManifest.xml file, for it to be recognized as an available service for use. That is simply a matter of adding a <service> element as a child of the application element, providing android:name to reference your service class.

Since the service class is in the same Java namespace as everything else in this application, we can use the shorthand (e.g., "PlayerService") to reference our class.

For example, here is a manifest showing the <service> element:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.commonsware.android.fakeplayer"
  android:versionCode="1"
  android:versionName="1.0">

  <supports-screens
    android:anyDensity="true"
    android:largeScreens="true"
    android:normalScreens="true"
    android:smallScreens="true"/>

  <uses-sdk
    android:minSdkVersion="14"
    android:targetSdkVersion="14"/>

  <application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@android:style/Theme.Holo.Light.DarkActionBar">
    <activity
      android:name="FakePlayer"
      android:label="@string/app_name">
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>

        <category android:name="android.intent.category.LAUNCHER"/>
      </intent-filter>
    </activity>

    <service android:name="PlayerService"/>
  </application>

</manifest>

Communicating To Services

The preview of this section was lost in the sofa cushions.

Scenario: The Music Player

The preview of this section is sleeping in.

Communicating From Services

The preview of this section left for Hollywood to appear in a reality TV show.

Scenario: The Downloader

The preview of this section is en route to Mars.

JobIntentService

The preview of this section was stepped on by Godzilla.

IntentService or JobIntentService?

The preview of this section is in the process of being translated from its native Klingon.

Services and Configuration Changes

The preview of this section was accidentally identified as an Android 'tasty treat' by the Cookie Monster.

When Do Services End?

The preview of this section is sleeping in.

Background Service Limitations

The preview of this section left for Hollywood to appear in a reality TV show.