There are quite a few misnomers when it comes to the Android Service class. Let’s clear some of them up.

What most people think of when they think of services

run independently of user interaction

don’t commonly have a GUI or can run without one

use a client for interaction (web browser, db client, sockets)

independent threading

long running

This is the common understanding of a UNIX service

How Android defines a service

long running

does not provide a user interface

independent of application lifecycle

can be “bound” to

You’ll notice that threading it not part of this. This is the source of great confusion for many developers. A service is in the “background” in that it does not interact with the user but it still runs on the main thread. The same thread that handles user interaction, View hierarchy updates and activity lifecycle events. When you start a service it is blocking user interaction.

This is rather inconvenient, so the SDK includes a class that puts the threading on a separate thread.

Introducing IntentService

http://developer.android.com/reference/android/app/IntentService.html

IntentService is a Service that has baked-in asynchronous handling. Every service (IntentService or regular Services) is started by a call to

Context . startService ( android . content . Intent )

a regular Service would then handle this Intent starting with onStartCommand using the main thread. If you were doing some long running operation (reading from a db, reading from the filesystem, long computation) you would need to create your own threading model, whether it be with an ExecutorService or using a Handler

IntentService does this work for you. It sends intents to a worker thread that calls a method you will be overriding called onHandleIntent(android.content.Intent) . All code in onHandleIntent will be done on a single worker thread.

A simple IntentService could look like this:

public class SimpleLoggingIntentService extends IntentService { /** * A constructor is the only other method you need to override. It's * important to call super with a string unique to this class as it will * be used to name the worker thread. */ public SimpleLoggingIntentService () { super ( "SimpleLoggingIntentService" ); } /** * This is called on the worker thread for each intent received through * startService */ @Override protected void onHandleIntent ( Intent intent ) { Log . d ( "SimpleLoggingIntentService" , "starting onHandleIntent" ) // Do work here (downloads, DB access, CPU intensive operations). We'll // simulate with a sleep call. try { Thread . sleep ( 5000 ); //sleep 5s. } catch ( InterruptedException ex ) { Log . e ( "SimpleLoggingIntentService" , ex . getMessage (), ex ); } Log . d ( "SimpleLoggingIntentService" , "finishing onHandleIntent" ) } }

This service passes and Intents sent to startService to onHandleIntent on a worker thread which will handle them in serial according to FIFO (first in first out).

Once all the intents have been handled, the IntentService is stopped.

When to use a Service instead of an IntentService

For most situations, an IntentService will handle all that you need. The threading model works well and is usually enough for most applications. However, there are times when a traditional Service is more appropriate. Let’s look at a multithreading example.

Let’s say we want to download lots of images to the app folder on the device. These images are small, maybe profile images at 64x64, but there are a lot of them. We could handle this in an IntentService. We could give an IntentService an Intent for each icon we want to download and it will execute them in serial. But that could be very slow. If we download them in parallel it will be much faster. Let’s create our own service that does this:

public class MultiThreadedService extends Service { public static final String _URL = "url" ; private ExecutorService executorService ; // counter for number of files we have downloaded private int downloadsStarted ; // counter for number of files done private int downloadsFinished ; private Handler handler ; @Override public void onCreate () { super . onCreate (); // let's create a thread pool with five threads executorService = Executors . newFixedThreadPool ( 5 ); downloadsStarted = 0 ; downloadsFinished = 0 ; handler = new Handler (); } @Override public int onStartCommand ( Intent intent , int flags , int startId ) { // lets say that we are sending the url in the intent String url = intent . getStringExtra ( _URL ); // create a runnable for the ExecutorService DownloadRunnable task = new DownloadRunnable ( getApplicationContext (), url , downloadsStarted ++); // submit it to the ExecutorService, this will be put on the queue and run using a thread // from the ExecutorService pool executorService . submit ( task ); // tells the OS to restart if we get killed after returning return START_STICKY ; } /** * we don't care about binding right now, returning null is the way to do that * * @param intent * @return */ @Override public IBinder onBind ( Intent intent ) { return null ; } /** * to be called by the dl task. if we have exhausted our list of dl's let's shutdown. */ private void finished () { if ( downloadsFinished == downloadsStarted ) { handler . post ( new Runnable () { @Override public void run () { Log . d ( "MultiThreadedService" , "downloaded " + downloadsFinished + " images, shutting down." ); stopSelf (); } }); } } /** * dl's the image in question to <index>.jpg */ private class DownloadRunnable implements Runnable { private static final int BUFFER_SIZE = 4096 ; private Context context ; private String url_str ; private int index ; public DownloadRunnable ( Context context , String url , int index ) { this . context = context ; this . url_str = url ; this . index = index ; } @Override public void run () { URL url = null ; HttpURLConnection httpConn = null ; try { url = new URL ( url_str ); httpConn = ( HttpURLConnection ) url . openConnection (); // opens input stream from the HTTP connection InputStream inputStream = httpConn . getInputStream (); String saveFilePath = context . getFilesDir () + File . separator + index + ".jpg" ; // opens an output stream to save into file FileOutputStream outputStream = new FileOutputStream ( saveFilePath ); int bytesRead = - 1 ; byte [] buffer = new byte [ BUFFER_SIZE ]; while (( bytesRead = inputStream . read ( buffer )) != - 1 ) { outputStream . write ( buffer , 0 , bytesRead ); } outputStream . close (); inputStream . close (); Log . d ( "MultiThreadedService" , "File downloaded to " + saveFilePath ); } catch ( Exception e ) { Log . e ( "MultiThreadedService" , e . getMessage (), e ); } finally { if ( httpConn != null ) { httpConn . disconnect (); } } downloadsFinished ++; finished (); } } }

This will download every image given to it using the ExecutorService but will return immediately from onStartCommand . Once all the images are downloaded the service will shut itself down. This runs independently of user interaction and offloads the slow download execution to worker threads. If you want to see all the code go to https://github.com/browep/ServicesTutorial.

Further Reading

There is a lot more to Services and anyone making a decently sized app should know when to use them and when not to. See: http://developer.android.com/guide/components/services.html for further reading.

$39 $18) when you signup for the newsletter. We won't send you spam. Unsubscribe at any time. Get the soon-to-be-released Responsive Android book at half off: ($18) when you signup for the newsletter.