Friday, March 18, 2011

Asynchronous tasks in Android applications

When we are writing an application and we want to perform a heavy background operation we have to start a new thread that will handle this operation and then publish the results on the UI thread for further processing. Having to manipulate threads can very often lead to complex pieces of code and it is pretty easy to mess things up really fast!

Android provides a class that enables proper and easy use of the UI thread and makes our life really easy. AsychTask is a class that allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers. An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, called Params, Progress and Result, and 4 steps (functions), called onPreExecute, doInBackground, onProgressUpdate and onPostExecute.

AsyncTask must be subclassed to be used and the subclass must override at least one method (doInBackground), and most often will override a second one (onPostExecute). Now let's take a look at the three types used by an asynchronous task:
  1. Params: The type of the parameters sent to the task upon execution.
  2. Progress: The type of the progress units published during the background computation.
  3. Result: The type of the result of the background computation.
If a type is not used by an asynchronous task, then this type is marked as unused using the type Void. Now let's take a look at the 4 steps a task goes through when it is executed:
  1. onPreExecute: Invoked on the UI thread immediately after the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
  2. doInBackground: Invoked on a background thread after onPreExecute finishes executing. This function is used to perform background operations/computations that can take a long time. In this function we can use publishProgress to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate step.
  3. onProgressUpdate: Invoked on the UI thread after a call to publishProgress. Usually it is used  to animate a progress bar.
  4.  onPostExecute: Invoked on the UI thread after doInBackground finishes executing. The result of the background computation is passed to this step as a parameter.
A task can be cancelled at any time by invoking cancel function. Below I am quoting an example of the use of AsynchTask:

package com.androidsnippet.AsynchronousTask;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;

public class AsynchronousTaskActivity extends Activity {
/** Called when the activity is first created. */
private ProgressBar mProgressBar;
private Button mCalculationButton;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
mCalculationButton = (Button) findViewById(R.id.calculation);

mCalculationButton.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
CalculationTask task = new CalculationTask();
task.execute();
}
});
}

/** Task that handles the procedure to store a route on the local database */
private class CalculationTask extends AsyncTask<Void, Integer, Long> {

@Override
protected void onPreExecute() {
// Initialize bar
mProgressBar.setProgress(0);
}

@Override
protected Long doInBackground(Void... data) {
// Store route
long counter = 0;
for(int i = 1; i <= 10000000; i++) {
counter += i;
if(i % 100000 == 0) {
publishProgress((int) i/100000);
}
}

return counter;
}

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

@Override
protected void onPostExecute(Long result) {
// Publish result
Toast.makeText(getApplicationContext(), "Counter is " + result, Toast.LENGTH_LONG).show();
}
}
}
By pressing the button a calculation starts in the background and every 10000 loops the progress bar is updated. When the calculation finishes the result is printed.

This is the end of the tutorial. I hope to find it useful. Find the project here and leave a comment if you want!