Using IntentService vs AsyncTask in Android

Kevin Hoffman
AndroidPub
Published in
6 min readJul 25, 2015

--

There’s a saying that has been appropriated by the programming community, “Hindsight is 20/20”. This is usually taken to mean that you learn valuable lessons only after the fact. Unfortunately, it rarely ever means that you have the time to go back and apply those lessons to your existing code. It is my contention that teams need to build “20/20 time” directly into their development process, to go back and deal with some of the lessons learned and right the various wrongs that have cropped up as scar tissue during long development cycles.

One very specific example of this kind of learning (the kind where you wish you could hop into a Delorian and tell your past self how to code it the right way and avoid the mistakes) for me was the distinction between an IntentService and an AsyncTask in Android development. I’ll explain what these are, how I used them incorrectly, and how to decide when to use either of them.

The IntentService is an extension of Android’s Service class. As such, Intent Services need to be registered in the application manifest, can be invoked either by your application or (if you allow) can be invoked by other applications. Intent Services are also designed specifically to handle background (usually long-running) tasks and the onHandleIntent method is already invoked on a background thread for you.

An AsyncTask is a class that, as its name implies, executes a task asynchronously. The AsyncTask is a generic class that takes 3 type arguments: the type of the arguments passed when starting the task, the type of arguments returned to the caller when reporting progress, and the type of the result. These are the params, progress, and result type parameters, respectively.

The rest of this blog post provides an overview of what I learned from stumbling blindly through an application development and making choices about which one of these tools to use and when.

Both of these classes allow you to execute some block of code in the background, asynchronously and on a different thread from the main thread so the UI is not blocked. This also means you can execute network code using either of these classes because network code is forbidden on the main thread in an Android application.

Lifetime

One thing to consider when deciding between these two classes is how long this background task will be around. Are you going to execute this block of code every 30 seconds, possibly to ping your back-end to make sure you have connectivity? Are you going to fire off this background task, do work, and then walk away? Do you need this task to continue to completion even if someone suspends your activity (they tap the home hardware button, they accept an incoming call, they swap to another previously suspended task) or are you okay with this task being terminated in a situation like this?

If you need a more durable background process, one that continue to completion even in the absence of a foreground controlling activity, then you want an IntentService. I don’t know if this is how they are actually implemented, but I think of them like daemon threads in regular server-side Java. An AsyncTask is going to be interrupted if the activity that launched it is suspended. There are a number of reasons for this, but the biggest one I can think of is that the task would no longer have anyone to whom to deliver progress or results.

An IntentService, by virtue of being a service, can be scheduled. This means you can create an alarm to run it once, or you can set up an alarm and run it every 30 seconds, every 24 hours, etc. These scheduled alarms are super lightweight, fairly easy to use, and offer a number of benefits. Using an IntentService in combination with repeating alarms, you can do a number of things like refresh someone’s social network feed, check the status of your backend services, update cached images, send “phone home” logging or analytics events to your infrastructure, etc.

Reporting Progress

Both IntentService and AsyncTask have the capability of reporting their progress. To report progress with an AsyncTask you just call the publishProgress method inside your doInBackground method. The AsyncTask class is designed specifically to perform a background task and report progress to the UI thread. As such, it’s the perfect candidate for performing background tasks that are initiated by, or dependent upon, some aspect of the UI. The onProgressUpdate method of the AsyncTask is invoked on the UI thread, so you don’t even have to write any code to forward your actions to that thread.

On the other hand, an IntentService does not have a publishProgress method, nor does it have any built-in facility for reporting anything to the UI thread. You can use an IntentService to perform UI-initiated and dependent tasks, but the experience is far from ideal. This was one of my biggest mistakes in doing asynchronous network tasks — I built everything on IntentService and paid the price by filling my application with needless complexity.

To report progress from inside an IntentService, you need to use Android’s built-in notifications facility. Let’s say you’re done downloading something, you might create an Intent with the String parameter “com.kotancode.demos.downloadservice.DONE” and then publish that you have completed a download by invoking the sendBroadcast() method with this intent.

This pub/sub facility for interacting with services is a key facility that underpins nearly everything that Android does, but it comes with a price in terms of complexity. Your activities need to subscribe to these publications, and when an activity is suspended (which can happen at unpredictable times), you have to remove the subscription, and re-subscribe when the activity resumes.

One word of caution when launching intent services or when reporting progress from within them via sendBroadcast: The maximum size of the bundle of data on an Intent is extremely small. For example (again: learned this the hard way), if you download an image from within an IntentService and try and put the image’s byte array in an intent to notify some activity of its completion, you may or may not be successful, depending on the maximum size of the Intent’s bundle, which can vary from device to device. Worse — your app won’t get a friendly exception in this case. No, instead it will silently fail to publish your intent and you’ll have to examine logcat to find out why.

It’s clear to me, now that I have my aforementioned “20/20 hindsight”, that if I want to push a button in the UI that interacts with a backend service, displays progress, and then updates the GUI when complete — I want to use an AsyncTask. On the other hand, if I want to interact with a service that may have been initiated by some other non-UI activity (such as a timer/alarm, or application startup), and I might have multiple different activities that are interested in listening to the events broadcast by this background service, then an IntentService is the way to go, and its complexity is warranted there.

Shared Functionality

One other key question to ask yourself when deciding between these two tools is whether or not you want to expose this functionality to other applications, either ones you wrote or ones written by anyone in the Android community.

There are countless examples of services available that come with applications that you can take advantage of today. For example, if your Android device has the “Barcode Scanner” application installed, then there is an IntentService you can invoke that will launch the barcode scanner, obtain a barcode, and then publish a broadcast letting your application (or any other application, for that matter) know the barcode that was just scanned. This is only possible with an IntentService, and this is why you need to declare intent services in your application’s AndroidManifest.xml file.

Summary

In conclusion, I think the most important guideline is this: use an AsyncTask if you can. AsyncTask is the simplest to use, the least prone to getting your application in a state where it stops caring about the events of a service, and still allows you to share code among your own apps by letting you create discrete subclasses of AsyncTask.

Only if you truly need the ability to run a background task in a way that is entirely decoupled from the UI, should you use an IntentService. Further, if you want to expose the functionality of your background task so that it is available to other applications, including ones you didn’t write, then you’ll need the IntentService.

I hope this blog post has not only cleared up some concepts around how to deal with background, asynchronous processing in Android, but hopefully you’ll learn from the mistakes I made so you don’t have to make them as well.

--

--

Kevin Hoffman
AndroidPub

In relentless pursuit of elegant simplicity. Tinkerer, writer of tech, fantasy, and sci-fi. Converting napkin drawings into code for @CapitalOne