Using an AsyncTask to download a file

  • Written by  Clive

AsyncTasks do it in the background

The golden thread

asyncTask tutorial icon

All Android components (like activities and services) start on the main thread. This is the thread that the user interacts with.

You need to keep this thread clear so that the app does not hang. It’s a good idea to put all time-consuming processes on a separate thread.

Put file operations, network lookups, database interaction, etc. on a background thread.

Enter AsyncTask

The AsyncTask class lets you put the heavy work in the background. It lets the user know when the work is finished.

The AsyncTask can also let the user know how the work is progressing.

The AsyncTask takes care of all the thread creation, management, and synchronization with the main thread. You don’t have to worry about it.

AsyncTasks are short

AsyncTasks are great for quick (a few seconds) background processing where you need to show the progress to the user.

 

Use a Service if your background process will last longer that a few seconds.

AsyncTasks can only be executed once

You start the AsyncTask by creating a new instance of it and then calling execute().

You can only call execute() once else you’ll get an error.

Our AsyncTask tutorial app

Running the app displays a progress bar and a button. Pressing the button starts an AsyncTask which downloads an image. The progress bar indicates the progress.

When the AsyncTask is finished, it displays the image and removes the progress bar.

AsyncTask tutorial app screenshot

Press the button to start the AsyncTask. It shows the progress of the download in a progress bar. When the download is finished, the progress bar is removed and the image displayed

Creating the AsyncTask

Our AsyncTask is an inner class.

Create an AsyncTask subclass by extending AsyncTask:

The AsyncTask sub-class

Our AsyncTask subclass

The AsyncTask types

The AsyncTask uses three types:

The AsyncTask types

Our AsyncTask types

AsyncTask<Params, Progress, Result>

The AsyncTask types: what they are?
  • Params – the type of parameters sent to the task
  • Progress – the type of progress units – used to show progress
  • Result – the type of the result of the background operation

Any or all of these can be Void.

The AsyncTask methods

The AsyncTask has 4 possible methods:

  • onPreExecute() – optional. Runs on the main thread. Used to set up the task. We set up the progress bar here
  • doInBackground(Params…) – does the work on a background thread. The parameters are passed here when execute() is called. Returns the result and can also publish units of progress
  • opProgressUpdate(Progress…) – optional. Runs on the main thread. Called by publishProgress(Progress…) in doInBackground(Params…). We use it to update our progress bar
  • onPostExecute(Result) – optional. Runs on the main thread. It receives the result of the background operation. We use it to display the image

Here’s our onPreExecute() method:

The AsyncTask preExecute() method

We set up the progress bar in onPreExecute(). It’s on the main thread

Note the following:

  • we get a reference to the progress bar in the layout file
  • PROGRESS_BAR_MAX – we set the maximum value for the progress bar here. Progress updates will continue to increase the colored bar as the file downloads. Once the download is finished, the progress value will have reached the maximum set here

Now for the part that does the work

Here’s the code for our doInBackground(Params…) method:

The AsyncTask doInBackground() method

The first part of the doInBackground() method

This is the first part of the method. Note the following:

  • params – this is the URL of the image as passed in the execute() method. You could pass a number of URL’s so your execute could look like this: execute(url1, url2, url3)
  • path – we’re going to download a file and save it. This is the path to the file that we will save
  • connection – we create a new internet connection object which we’ll use to download the file
  • try – we put the connection, download and saving of the file within a try/catch/finally statement to take care of any problems without crashing the app
  • url – we get the first URL out of params (even though there is only one)
  • openConnection() – connects to the given url

Showing a progress dialog

You can use a progress dialog instead of a progress bar to show the status of the download.

Bear in mind that the dialog displays on the main thread. The user will have to wait for it to dismiss before being able to interact with the app.

The ProgressDialog screenshot

You can use a Progress Dialog if you wish but it runs on the main thread

 

To show the dialog, include this code in the onPrexecute() method (and remove the progress bar code):

The ProgressDialog code to show

Use this code to display a progress dialog

 

To dismiss the dialog when the download is finished. Include this code in the onPostExecute() method:

The ProgressDialog code to dismiss

Use this code to dismiss the progress dialog

We’re using the progress bar

Continuing with the doInBackground() method.

We’ve included a progress bar in the layout file. We want the colored bar to increase as the download progresses. Here’s one way of doing that:

The doInBackground() code to get the progress status

One way of getting a value to show the status of the download

Without going into detail, we get the size of the file and calculate a value for each increment in the download.

These incremental values are passed on to the onProgressUpdate(Integer…progress) method by calling publishProgress(i):

The onProgressUpdate() method

This method receives incremental values as the download proceeds. These values are used to set the position of the progress bar

This sets the progress bar to the new value (and the colored bar moves closer to the maximum).

Continuing with the doInBackground() method.

Here’s the remainder of the code:

The doInBackGround() method for downloading

The remainder of the doInBackground() code

We read the file from the url and save it on the device. The catch statement takes care of any errors. We close the connection in the finally statement.

Once the download is finished, we set the progress bar to its maximum and return the path to the saved file. onPostExecute() is called.

Knock-off time: the work’s done so we notify the main thread

Here’s the code for the onPostExecute() method:

The onPostExecute() method

This runs on the main thread and updates the User Interface

This runs on the main thread. It receives the path to the saved file from the doInBackground() method once the work is finished.

Note the following:

  • we no longer need the progress bar so we make it invisible
  • we get the image by decoding the saved bitmap file
  • we display the image in the image view

It all started with a button press

We’re using the AsyncTask to download an image. Here’s the URL:

The download image URL

The URL of the image that we want to download

Pressing the button starts the AsyncTask. Here’s the button code:

The button code

Pressing the button starts the download in an AsyncTask

 

We create a new instance of our AsyncTask and then call execute(). We pass the image URL as a parameter.

 

The AsyncTask will take care of the rest, downloading the file, notifying the user of the progress and eventually displaying the image.

 

Here's a great AsyncTask video tutorial that I'm sure you will find helpful.

Note that the AsyncTask is not bound to the activity in which it was created. The AsyncTask will run until it has completed it's task. On the other hand, the activity may die before the AsyncTask has completed it's task. The AsyncTask will then try to update the UI of the original activity (if required) and may throw an exception because the activity no longer exists. You need to be aware of this and construct your code accordingly.

 

I hope that you have found this tutorial helpful.

This tutorial was created using Android Studio. You can download the project files here Download icon

Are you using Eclipse or another IDE? Here's how you can use this project's Android Studio files.