My Android AsyncTask docs and examples (parameters, callbacks, executing, canceling)

I’ve currently written this document as a “note to self” about how the Android AsyncTask works. It’s currently incomplete, but if you want to know how an AsyncTask works, most of the answers are generally here. I provide documentation for most aspects of the AsyncTask, though my coverage of (a) updating progress/status and (b) canceling an AsyncTask is a little weak atm.

So ... if you can understand my cryptic notes, here’s a lot of what you need to know on how to use an Android AsyncTask.

Note

In this document I often use descriptions that come directly from the Android docs. I don’t cite all of those because it gets repetitive after a while. (If anything sounds particularly smart, it probably came from that document.)

Introduction

The key concept:

You use an Android AsyncTask to execute some long-running code that needs to update the UI. The idea is that you (a) run your long-running task on another thread, and then (b) that thread updates the UI when it finishes running.

Conversely, if you block the UI by trying to run a long-running task on the main thread, you will probably get the dreaded, “Application Not Responding” (ANR) error. (No good developer wants an ANR.)

Here are a few quotes to expand on that:

  • An asynchronous task (AsyncTask) is defined by a computation that runs on a background thread and whose result is published on the UI thread.
  • AsyncTask creates a background thread for you, and runs the code in the doInBackground method on that thread.
  • onPostExecute is run after doInBackground, and it's run on the main/ui thread, so you it's safe to update ui components from it. (this is the correct way to update ui components.)

The first quote comes from the official Android docs, and the last two quotes come from the book, Android Programming: The Big Nerd Ranch Guide.

Quick intro: How to define and use an AsyncTask

You create a new task by extending the AsyncTask class. Here’s a short example:

private class DeleteImagesTask extends AsyncTask<Void, Void, Void> {

    @Override
    protected Void doInBackground(Void... params) {
        // this might take a while ...
        deleteSelectedGalleryItems();
        return null;
    }

    @Override
    protected void onPostExecute(Void param) {
        galleryItemAdapter.notifyDataSetChanged();
    }
}

You run/execute this specific task like this:

new DeleteImagesTask().execute();

Other tasks can take input parameters, and also have a return type.

AsyncTask’s three parameters

Every time you extend an AsyncTask, you must declare the three data types that it will use:

android.os.AsyncTask<Params, Progress, Result> 

Those three types are:

  • Params — the type of the parameters sent to the task upon execution
    • the type of parameters passed into execute()
  • Progress — the type of the progress units published during the background computation
  • Result — the type of the result of the background computation
    • must be the return type of doInBackground

Those types are shown in the following image:

Android AsyncTask parameter types

In this example, a URL is passed into the AsyncTask, the progress units are Integer, and the result of the background task is a Long. (You can see the complete code for this class later in this tutorial.)

AsyncTask runs in four steps

Directly from the Android docs, an AsyncTask runs in four sequential steps:

  1. onPreExecute() — invoked on the UI thread before the task is executed
  2. doInBackground(Params...) — invoked on the background thread immediately after onPreExecute() finishes executing
  3. onProgressUpdate(Progress...) — invoked on the UI thread after a call to publishProgress(Progress...)
  4. onPostExecute(Result) — invoked on the UI thread after the background computation finishes

AsyncTask callback methods

The AsyncTask API defines a set of callback methods. This method is required:

  • doInBackground(Params...)
    • required
    • do your long-running work here
    • the input parameters from execute are passed into this method
    • invoked on the background thread immediately after onPreExecute

This method is almost always used:

  • onPostExecute(Result)
    • used to update the ui
    • not required, but often used

Methods that are used less often:

  • onProgressUpdate(Progress...)
    • invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing
  • onPreExecute()
    • invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface
  • onPostExecute(Result)
    • invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.

TODO: I need to document these and show examples of them:

  • onCancelled(Result result) — runs on the UI thread after cancel(boolean) is invoked and doInBackground(Object[]) has finished
  • publishProgress(Progress... values) — can be invoked from doInBackground(Params...) to publish updates on the UI thread while the background computation is still running

How to run/execute an AsyncTask

Given a class named DownloadFilesTask that extends AsyncTask, you run the task like this:

new DownloadFilesTask().execute(url1, url2, url3);

This example comes from the Android docs, and the complete source code is shown below.

AsyncTask example: My RestTask

This is from my Android RestTask example. First, here’s the AsyncTask:

public class RestTask extends AsyncTask<HttpUriRequest, Void, String>
{
    private static final String TAG = "AARestTask";
    public static final String HTTP_RESPONSE = "httpResponse";

    private Context mContext;
    private HttpClient mClient;
    private String mAction;

    public RestTask(Context context, String action)
    {
        mContext = context;
        mAction = action;
        mClient = new DefaultHttpClient();
    }

    public RestTask(Context context, String action, HttpClient client)
    {
        mContext = context;
        mAction = action;
        mClient = client;
    }

    @Override
    protected String doInBackground(HttpUriRequest... params)
    {
        try
        {
            HttpUriRequest request = params[0];
            HttpResponse serverResponse = mClient.execute(request);
            BasicResponseHandler handler = new BasicResponseHandler();
            return handler.handleResponse(serverResponse);
        }
        catch (Exception e)
        {
            // TODO handle this properly
            e.printStackTrace();
            return "";
        }
    }

    /**
     * `onPostExecute` is run after `doInBackground`, and it's
     * run on the main/ui thread, so you it's safe to update ui
     * components from it. (this is the correct way to update ui
     * components.)
     */
    @Override
    protected void onPostExecute(String result)
    {
        Log.i(TAG, "RESULT = " + result);
        Intent intent = new Intent(mAction);
        intent.putExtra(HTTP_RESPONSE, result);

        // broadcast the completion
        mContext.sendBroadcast(intent);
    }

}

Here’s how I run this AsyncTask:

try
{
    HttpGet httpGet = new HttpGet(new URI(TEST_URL));
    RestTask task = new RestTask(getActivity(), ACTION_FOR_INTENT_CALLBACK);
    task.execute(httpGet);
    progress = ProgressDialog.show(getActivity(), "Getting Data ...", "Waiting For Results...", true);
}
catch (Exception e)
{
    Log.e(TAG, e.getMessage());
}

AsyncTask example: A “Void, Void, Void” example

Next, here’s an AsyncTask that I call with three Void parameters:

private class DeleteImagesTask extends AsyncTask<Void, Void, Void> {

    /**
     * `doInBackground` is run on a separate, background thread
     * (not on the main/ui thread). DO NOT try to update the ui
     * from here.
     */
    @Override
    protected Void doInBackground(Void... params) {
        deleteSelectedGalleryItems();
        return null;
    }

    /**
     * `onPostExecute` is run after `doInBackground`, and it's
     * run on the main/ui thread, so you it's safe to update ui
     * components from it. (this is the correct way to update ui
     * components.)
     */
    @Override
    protected void onPostExecute(Void param) {
        cleanupUiAfterCancelOrDelete();
        galleryItemAdapter.notifyDataSetChanged();
    }
}

I call this AsyncTask like this:

new DeleteImagesTask().execute();

In order, the three AsyncTask parameters are Void because:

  • I don’t pass any values into the AsyncTask
  • The AsyncTask doesn’t provide any progress update information
  • The AsyncTask has no return value

AsyncTask example: My FetchItemsTask

In this AsyncTask example I do some work in the background and return an ArrayList<String>:

private class FetchItemsTask extends AsyncTask<Void,Void,ArrayList<String>> {
    @Override
    protected ArrayList<String> doInBackground(Void... params) {
        ArrayList<String> quotes = DatabaseManager.get(getActivity()).getAllActiveQuotes();
        return quotes;
    }

    @Override
    protected void onPostExecute(ArrayList<String> items) {
        mItems = items;
        setupAdapter();
    }
}

The first two parameters are Void because:

  • I don’t need any values passed into the AsyncTask
  • The AsyncTask doesn’t provide any progress update information

AsyncTask example: Example from the Android docs

The Android AsyncTask docs shows this class:

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {

    protected Long doInBackground(URL... urls) {
        int count = urls.length;
        long totalSize = 0;
        for (int i = 0; i < count; i++) {
            totalSize += Downloader.downloadFile(urls[i]);
            publishProgress((int) ((i / (float) count) * 100));
            // Escape early if cancel() is called
            if (isCancelled()) break;
        }
        return totalSize;
    }

    protected void onProgressUpdate(Integer... progress) {
        setProgressPercent(progress[0]);
    }

    protected void onPostExecute(Long result) {
        showDialog("Downloaded " + result + " bytes");
    }

}

This is a good example because it gives you an idea of how to update the progress from an AsyncTask.

This task is started like this:

new DownloadFilesTask().execute(url1, url2, url3);

Note that DownloadFilesTask is defined like this:

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {

The three AsyncTask data type parameters work like this:

  1. URL is what is passed into execute
    • execute then passes this into doInBackground as URL... urls
  2. Integer is the type of the progress units published during the background computation
    • these “progress units” are published with the publishProgress method call in doInBackground
    • this value is passed into onProgressUpdate as Integer... progress
    • onProgressUpdate calls a method named setProgressPercent that isn’t shown, but presumably updates the UI
  3. Long is the type of the result from the background computation
    • therefore, it is the type that is returned by doInBackground
    • it is also passed into onPostExecute as Long result

Visually, the three AsyncTask input parameters map to the source code as shown in this image:

How the Android AsyncTask parameter types map to the source code

How to cancel an AsyncTask

If you need to cancel an AsyncTask, you do so by calling the cancel(boolean) method on it. Here’s an example:

DownloadFilesTask task = new DownloadFilesTask().execute(url1, url2, url3);

// some time later ...

task.cancel(false)

When you cancel the task with cancel(false), this is a “polite” way to cancel a task. It assumes that you have implemented an isCancelled check in your doInBackground method, as shown in the Google/Android example above:

if (isCancelled()) break;

You can also cancel a task with cancel(true). This is considered an “impolite” way to cancel a task, and it interrupts the thread doInBackground is running on.

If possible, it’s always preferred to use the cancel(false) call.

More ...

A few more notes about AsyncTask from the excellent book, Android Programming:

  • AsyncTask is intended for work that is short-lived and not repeated too often
  • If you’re creating a lot of AsyncTasks or using them to run something for a long time, you’re probably using the wrong tool
  • AsyncTask does not create a thread for each instance; by default, it uses an Executor to run all AsyncTasks on the same thread (i.e., multiple tasks run one after another, not in parallel)

I’ll come back and reorganize this article when I have more time, but for today I just wanted to put my initial AsyncTask notes and examples out here in the hopes that they may help someone else.