Table of Contents
- Note
- Introduction
- Quick intro: How to define and use an AsyncTask
- AsyncTask’s three parameters
- AsyncTask runs in four steps
- AsyncTask callback methods
- How to run/execute an AsyncTask
- AsyncTask example: My RestTask
- AsyncTask example: A “Void, Void, Void” example
- AsyncTask example: My FetchItemsTask
- AsyncTask example: Example from the Android docs
- How to cancel an AsyncTask
- More ...
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 thedoInBackground
method on that thread.onPostExecute
is run afterdoInBackground
, 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()
- the type of parameters passed into
Progress
— the type of the progress units published during the background computationResult
— the type of the result of the background computation- must be the return type of
doInBackground
- must be the return type of
Those types are shown in the following image:
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:
onPreExecute()
— invoked on the UI thread before the task is executeddoInBackground(Params...)
— invoked on the background thread immediately afteronPreExecute()
finishes executingonProgressUpdate(Progress...)
— invoked on the UI thread after a call topublishProgress(Progress...)
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
- invoked on the UI thread after a call to
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 finishedpublishProgress(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:
URL
is what is passed intoexecute
execute
then passes this intodoInBackground
asURL... urls
Integer
is the type of the progress units published during the background computation- these “progress units” are published with the
publishProgress
method call indoInBackground
- this value is passed into
onProgressUpdate
asInteger... progress
onProgressUpdate
calls a method namedsetProgressPercent
that isn’t shown, but presumably updates the UI
- these “progress units” are published with the
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
asLong result
- therefore, it is the type that is returned by
Visually, the three AsyncTask
input parameters map to the source code as shown in this image:
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
AsyncTask
s 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 allAsyncTask
s 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.