A comprehensive Guide to AsyncTask in Android Development

Async Task: Because sometimes you just need to tell your app to hold on, take a breath, and come back with the data when it's good and ready

Let's get started!

AsyncTask is used for handling background operations in Android applications. It allows long-running tasks, such as networkordatabaseoperations, without blocking the main (User Interface) thread, which can cause the application to become unresponsive and generate ANR errors.

Network Operations?

A network operation involves sending or receiving data over a network. This can include sending HTTP requests to a web server, downloading or uploading files, accessing databases remotely, and more. Most of the time, developers uses API to communicate with the server.

For example, a weather app may use network operations to retrieve the latest weather information from a remote server, while a social media app may use network operations to upload a photo to a user's account.

Database Operations?

A database operation involves interacting with a database (either local or remote database) which is a structured collection of data that can be queried, updated, and managed.

The database operations include inserting, updating, deleting, and retrieving data from a database.

With AsyncTask, developers can easily create a separate thread to execute a task, and then communicate the results back to the main thread once the task is complete.

AsyncTask takes care of thread management and provides methods for handling progress updates, intermediate results, and completion of tasks.

The code below represents the syntax of AsyncTask:

private class AsyncTaskThatRocks extends AsyncTask<Params, Progress, Result> {

    @Override
    protected void onPreExecute() {
        // This method runs on the UI thread before the background task starts
    }

    @Override
    protected Result doInBackground(Params... params) {
     
        // Params can be anything for example a custom class, or an Integer or 
        // may be a String
        
        // This method runs on a separate thread and performs the background task
        // We can access the input parameters using params[0], params[1], etc.
        // We can publish progress updates using publishProgress()
        // We can return the result of the background task
        return result;
    }

    @Override
    protected void onProgressUpdate(Progress... values) {
        // Progress can be Integer as we may need to update the progress between
        // 0 to 100 
        
        // This method runs on the UI thread and updates the UI with progress 
        // updates and can access the progress updates using values[0], values[1],
        // etc.
    }

    @Override
    protected void onPostExecute(Result result) {
        // Result can be anything for example a custom class, or an Integer or 
        // may be a String
        
        // This method runs on the UI thread after the background task completes
        // You can update the UI with the result of the background task
    }
}

AsyncTask has four key methods that need to be implemented:

  1. onPreExecute()

  2. doInBackground()

  3. onProgressUpdate()

  4. onPostExecute()

1. onPreExecute()

This is the first method that is executed in an AsyncTask.

The onPreExecute method is a callback method that is executed on the UI thread before the doInBackground method of AsyncTask is executed. This method is typically used to set up the task and to display any progress indicators to the user.

For example, if an AsyncTask is used to download a file from the internet, the onPreExecute method can be used to display a progress bar to the user, indicating that the download process has started. The progress bar can be updated in the onProgressUpdate method to show the progress of the download.

Another common use of onPreExecute is to disable any UI controls that should not be accessed while the task is running, such as buttons or text fields. This can prevent the user from interacting with the app in a way that might interfere with the task.

It's important to note that the onPreExecute method runs on the UI thread, so any long-running or blocking operations should be avoided. If a long-running operation is required, it should be performed in the doInBackground method.

2. doInBackground()

doInBackground() is the main method of AsyncTask that is executed in a background thread. This method performs long-running tasks or operations such as downloading data from the internet or performing complex calculations, without blocking the UI thread.

Here's an example implementation of doInBackground() method which fetches the age of Selena Gomez from the Internet:

@Override
protected String doInBackground(Void... voids) {
    int ageOfSelenaGomez = 0;
    try {
    
        // Perform a long-running task such as to fetch the age of Selena Gomez          
        // from the internet
        ageOfSelenaGomez = fetchAgeOfSelenaGomez();
    
    } catch (Exception e) {
        e.printStackTrace();
    }
    return ageOfSelenaGomez;
}

The implementation of method fetchAgeOfSelenaGomez() is not provided as it's currently not necessary to understand how the method will fetch the age. But its important to note that the method fetchAgeOfSelenaGomez() will take some amount of time as it performs a network request hence we call it long running task/operation.

It's important to note that doInBackground() method runs on a separate background thread and not on the main or the UI thread. Therefore, we should not perform any operations that update the UI in this method, as it will cause an exception.

If we want to update the UI with the progress of current operation/task, we can use the onProgressUpdate() method to publish the progress of the task and onPostExecute() method to publish the result of the task.

3. onProgressUpdate()

When a task is executed using AsyncTask, the doInBackground method runs in the background thread, while the UI thread remains free to interact with the user interface. onProgressUpdate method can be used to communicate the progress of the task to the UI thread.

To use onProgressUpdate, we must first define the data type that will be used to represent the progress of the task. This data type will be used as the argument type for the publishProgressmethod that is called from the doInBackground method to notify onProgressUpdate about the progress update.

The data type can be passed as a type parameter when we extend the AsyncTask class. For example:

public class AsyncTaskThatRocks extends AsyncTask<Void, Integer, Void> {
    // Async Task Implementation
}

In this example, Void (the first parameter) is used for the input parameter type of doInBackground, we have used Void as the task doesn't take any input.

Integer is used for the data type of the progress updates, and the last parameter Void is used for the return type of doInBackground.

It is important to note that the second type parameter (Integer in this example) is used as the data type for updating the progress because the progress can be between 1 to 100.

Once we have defined the data type, we can use the publishProgress method inside the doInBackground method to notify the onProgressUpdate method about the progress updates.

Lets say for example we have to send a progress of 69% to the UI, we can use the following code to publish a progress update of 69%:

publishProgress(69);

Then, inside the onProgressUpdate method, we can update the user interface to show the current progress:

@Override
protected void onProgressUpdate(Integer... currentProgress) {
    uiProgressBar.setProgress(currentProgress[0]);
}

The reason to use the currentProgress as an array ( currentProgress[0] ) is that is that the class AsyncTask takes a variable number of arguments, which is denoted by the ellipsis (...) in the method signature. This means that we can pass any number of arguments of the specified type to the methods.

In the case of onProgressUpdate, the specified type is Integer that we defined when we extended the AsyncTask class.

The Integer... syntax means that progress is an array of integers. This allows us to pass any number of integer values to the method as progress updates.

This is the reason we have used currentProgress[0] in our case as the variable is array.

To pass multiple integer values to onProgressUpdate method in AsyncTask, we can use an Integer array that holds the values we want to pass. For example:

public class AsyncTaskThatRocks extends AsyncTask<Void, Integer, Void> {

    @Override
    protected Void doInBackground(Void... voids) {
        // perform some work and update progress
        int[] progress = {50, 69, 100};
        publishProgress(progress);
        return null;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        int[] progress = new int[values.length];
        for (int i = 0; i < values.length; i++) {
            progress[i] = values[i];
        }
        // do something with the progress values
    }
}

4. onPostExecute()

onPostExecute() is called when the background operation initiated by doInBackground() method is completed. The method onPostExecute() runs on the main or UI thread and allows us to update the User Interface or perform any necessary post-processing operations after the completion of the background task.

The onPostExecute() method is useful when you need to update the UI elements such as progress bars, text views, or any other UI components with the results obtained from the background task. It can also be used to perform any final computations or processing on the results obtained from doInBackground().

For example:

private class AgeFetcherBackgroundTask extends AsyncTask<Void, Void, Integer > {
    protected String doInBackground(Void... params) {        
        // fetches the age of Salena Gome from the internet       
        Integer age = fetchAgeOfSalenaGomez();        
        return age;    
    }
    protected void onPostExecute(Integer result) {
        // Update UI with result        
        textView.setText(“Age:+ result);    
    }
}

The onPostExecute method is overridden to receive the Integer result returned by the doInBackground method and update the UI by setting the text of a TextView widget with the fetched age.

Summary till now!

AsyncTask is an Android class that provides a way to perform background tasks on a separate thread and update the UI with the results. It simplifies the process of performing long-running tasks in the background without blocking the UI thread, which can cause ANR (Application Not Responding) errors.

It is a generic class with three type parameters: Params, Progress, and Result.

private class MyAsyncTask extends AsyncTask<Params, Progress, Result> {
}
  1. Params: This is the type of the input parameters that are passed to the doInBackground() method of the AsyncTask. For example, if you want to fetch some data from a web service, you may pass a URL as the input parameter.

  2. Progress: This is the type of the progress updates that can be published by the publishProgress() method of the AsyncTask. The publishProgress() method is called from the doInBackground() method to publish the progress of the background computation to the UI thread. For example, if you are downloading a large file, you may want to update the progress bar in the UI with the current progress.

  3. Result: This is the type of the result that is returned by the doInBackground() method of the AsyncTask. For example, if you are fetching some data from a web service, the result may be a string or a JSON object that contains the fetched data. The onPostExecute() method of the AsyncTask receives this result and updates the UI with the fetched data.

It has four important methods which are as follows:

  1. onPreExecute(): This method runs on the UI thread before the background task starts. It is typically used to set up any necessary UI components, such as progress bars or text fields.

  2. doInBackground(): This method runs on a separate thread and performs the background task. It takes in the input parameters specified in the class definition, which are passed to it as an array. It should not access or modify any UI components.

  3. onProgressUpdate(): This method runs on the UI thread and is called by publishProgress(). It allows the background task to provide updates on its progress, such as updating a progress bar or displaying a message.

  4. onPostExecute(): This method runs on the UI thread after the background task completes. It receives the result of the background task as a parameter and can update any necessary UI components with the result.

Canceling AsyncTask

To cancel an AsyncTask in Android, we can call the cancel() method on the AsyncTask instance.

Here's an example of how to cancel an AsyncTask:

// Create an instance of your AsyncTask
AgeFetcherBackgroundTask task = new AgeFetcherBackgroundTask();

// Start the task
task.execute();

// To cancel the task, call the cancel() method
task.cancel(true);

If we call cancel(true) on an AsyncTask, it will set the cancellation flag to true and interrupt the doInBackground() method if it is currently running and will trigger onCancelled() method.

This means that if doInBackground() is currently executing a long-running operation that cannot be interrupted, an InterruptedException will be thrown, and the thread running doInBackground() will be terminated. Therefore, we should handle InterruptedExceptions within ourdoInBackground() method to ensure that the task can be stopped cleanly.

What if we call cancel(true)

When we call cancel(true) on an AsyncTask, it will interrupt the task and cancel its execution. This means that if the task is currently running, its doInBackground() method will be interrupted and the AsyncTask will immediately move to its onCancelled() method. This can be useful if we want to stop a long-running task as soon as possible.

What if we call cancel(false)

When we call cancel(false) on an AsyncTask, it will allow the task to complete its current execution. This means that if the task is currently running, its doInBackground() method will continue to run until it completes, and only then will the AsyncTask move to its onCancelled() method. This can be useful if we want to allow the task to complete its work and then perform some clean-up tasks in the onCancelled() method.

It's important to note that regardless of which cancel() method we call, the onCancelled() method of the AsyncTask will be called. However, the behavior of the doInBackground() method will differ depending on which cancel() method we use.

Last updated