Android 201: Recent AsyncTask Changes

android201async

Welcome back to Android 201, our series of posts aimed at the Android developer that already has some experience.  In other words, this is not an Android 101 column focused on teaching new developers how to make an Android app it is a column focused on teaching developers more about Android.

Android 201: Recent AsyncTask Changes

Ever since the first time I read the blog post “Painless Threading” over on the Android Developers blog I have used AsyncTasks quite often in my code.  Just about any time I have an operation that might slow down the user interface I just throw together an AsyncTask and have it run in the background.  The class is extremely easy to use.

One of my current projects is an open source project named AbianReader.  This project is an Android Library that can easily make an Android application that serves as a nice looking feed reader for a web site.  I use an AsyncTask to fetch an RSS stream and it is very handy.  The following is an oversimplified excerpt from that project.

I can start the task by doing a simple

new RefreshFeedTask().execute(feedUrlString);

That will start my task.  I override 3 methods for this task, doInbackground, onPreExecute, and onPostExecute.  doInBackground runs on a separate thread from the GUI, allowing me to do blocking network IO without hanging the GUI and causing an “Application Not Responding” error (aka ANR) for the user.  The onPreExecute and onPostExecute methods run on the GUI thread before and after the doInBackground method is called.

private class RefreshFeedTask extends AsyncTask
{
    @Override
    protected Void doInBackground(String... params)
    {
        // this thread is NOT ran on the UI thread
        // it is extremely useful for long running tasks

        // I pass the url that I want to connect to in the parameters
        String urlToConnectTo = params[0];

        // now that I have the URL I want to connect to I can pull down my feed
        // and not worry about hanging the UI thread

        return null;
    }

    @Override
    protected void onPreExecute()
    {
        // this function is ran on the GUI thread
        // this is very handy to do some last second checks
        // one check I do is to make sure that a network connection is available
        // if there is no netowrk connection I can save myself resource by just canceling the AsyncTask
    }

    @Override
    protected void onPostExecute(Void param)
    {
        // this function is also ran on the GUI thread
        // this is very helpful because I can now update my GUI
        // with the data I downloaded while in the doInBackground function
    }
}

While browsing my twitter feed a few months ago I read a rather disturbing tweet

I was immediately intrigued and went to read the very insightful post Mr. Murphy put together.  The post does a good job at summarizing the thread on the Android Developers Google Group where the behavior change was described.  Basically what has happened is that if you set a target SDK for your Android application to be 13+ the AsyncTask will run by default with a Executor that will only run one task at a time.  In previous versions of the SDK AsyncTask would run tasks in parallel.

For someone like me, this can be a big deal.  In the previously mentioned project, AbianReader, I was at one point using an AsyncTask to download the thumbnail images from posts. I would have up to 10 AsyncTasks running at once to get 10 unique thumbnails. If I was still using the AsyncTask to do this I would expect for all 10 tasks to be running in parallel, not one after the other. I needed the thumbnails to download as fast as possible so that the user can see the thumbnail for the post in the list of articles. If the thumbnail images downloaded one at a time the user experience would be rather poor because the user would be waiting for quite awhile for all of the thumbnails to be populated. If I were still using an AsyncTask it would work as expected with the target SDK set to something below 13, but once I set it to SDK 13 or higher than I would have a problem on my hands.

I think this is a good example of why it is not always best to just mindlessly bump your android:targetSdkVersion in your code unless there is some actual benefit to going to a higher SDK target.  Personally I generally set the minimum SDK to 4 (Android 1.6) for multiple screen size support and the target SDK 8 (Android 2.1) for multitouch support.

Fortunately there is a solution to restore the original behavior of AsyncTask and it is rather simple. I highly recommend taking the time to read through the original thread where this issue was discovered as well as Mr Murphy’s post describing the issue and offering a solution.

I hope this post gave Android developers a decent warning if they were not already aware.  If there are any topics that you would like to see covered in future Android 201 posts let me know in the comments below!


Sean Catlin

Sean Catlin is a software developer that current spends most of his development time creating applications for mobile devices. His company snctlnSoftware (http://snctln.com) has been publishing Android applications since December of 2008 and has had over 5 million application downloads during that time.

Related posts

Top