Advertisements

Multitasking in Android

As our technology happily rolls forward we want it to do more, and look nicer. We want our load times fast, and our interfaces smooth. Above all else, we never want to see a frozen screen. The key to your success is threading. Your new mantra, whether you like it or not, is “Keep it off the main thread!”

Why we thread

When you application starts, it creates a single thread called “main” or “the main thread”. This thread is responsible for pretty much everything regarding drawing views, and handling events triggered by the user. This is why it is often called the “UI Thread”. It is also the thread that your Activity’s onCreate() method runs in, as well as all of your view’s onMeasure() and onDraw() methods. In fact, just about everything in the Android SDK that starts with the word ‘on’ runs on the main thread.

The most important detail is that everything the user sees and does happens on the main thread. Therefore, any kind of long, slow, and or blocking operations done on this thread will cause the user interface to lag. This brings us to rule number one of concurrency in Android (and any other platform for that matter):

1. NEVER PERFORM BLOCKING OPERATIONS ON THE MAIN THREAD

This includes heavy computing, loading large amounts of data from disk, and any kind of network communication. All of these tasks should be designed to run “in the background” on another thread, and the user should be presented with some kind of indication that work is being done (such as an activity spinner, or a progress bar).

The second rule is equally important:

2. NEVER ACCESS THE GUI FROM ANOTHER THREAD

This includes any alterations to your view hierarchy at all. Don’t set labels, don’t change state, don’t edit a list, nothing. Usually the end result of a network operation will be to update the user interface, so you will need a way to schedule tasks on the main thread.

There are three convenience methods Google suggests you use when updating the user interface from another thread. Those methods are Activity.runOnUiThread(Runnable), View.post(Runnable), and View.postDelayed(Runnable).

Thread (class)

The simplest way to run code on another thread is via the conveniently named Thread class. This class does exactly what you’d expect it to do: it runs code on another thread. Threads created using the Thread class take a Runnable, which supplies a run method like this:

Thread t = new Thread( new Runnable() {
	public void run() {
		// thread code here
	}
});
t.start();

That’s about it! This thread will run until its run method is completed. If it contains an infinite loop, it will run forever. Threads are children of the application process and can run as long as the process is running. This can be very dangerous for performance if you have a “runaway thread” or if you implement poor synchronization (a subject I won’t be covering here) causing deadlock. So be careful, especially if you are implementing any complex concurrent algorithms.

The most common use for threading on Android is to fetch some data from the Internet and display it to the user. This kind of task will look something like this:

Thread t = new Thread( new Runnable() {
	public void run() {
		// perform network operations

		someView.post(new Runnable() {
			// update user interface
		});
	}
});
t.start();

To learn more about network communications, you can read my article found here

Timer and TimerTask

The Thread class is very useful when running a one-time task, or for long running background tasks (like a worker thread), but is not well suited for repeating timed tasks. In theory you could build a Thread with a loop and some timing code, but these methods are often imprecise and consume too much processor time. So, for a repeating background task it is best to use Timer.

Timer is a special threading mechanism that will run a given TimerTask (similar to Runnable) according to a given delay and offset. Timer is ideal for scheduling regular UI updates, or if you are implementing a game engine. Here is an example:

Timer timer = new Timer();
timer.schedule(new TimerTask() {
	// repeating code here
}, 0, 200);

This timer will execute immediately, and then repeat every 200 milliseconds. It is important to note that Timer operates on a single thread, so if your operation takes longer to run than your interval, the tasks will begin to back up (very bad). Note that a timer can be canceled (which you should do in your Activity’s onPause() method), but it will only cancel queued tasks, not currently running tasks.

AsyncTask: better than Thread

Threading is hard. It presents a whole world of issues that are only made worse by the Activity lifecycle. Your Android app can be started, paused, backgrounded, or killed at any moment. The last thing you want is for a thread to continue running after your Activity has ended, causing crashes and all kinds of trouble. It is totally possible to handle these situations using Thread, but it isn’t easy.

So in order to make your life easier, Google has made a wonderful convenience class called AsyncTask which encapsulates everything needed to perform a background task, and update the user interface as it runs. Note, that this is not considered a “general-purpose” threading solution. It is intended for things like async data loads and networking.

AsyncTask is an abstract class, meaning it provides some of the implementation for you. All you need to do is implement a handful of methods and you’ll have a working background thread. To make an AsyncTask you’ll do a few things:

  • Create a subclass of AsyncTask, which is and abstract class.
  • Choose your generic types: Param, Progress, and Result.
  • Override doInBackground(…) and onPostExecute(…) (as a minimum). You may also wish to override onProgressUpdate(…)
public class ContactWebserviceTask extends AsyncTask {
	protected String doInBackground(URL... params) {
		for (int x = 0; x < params.length; x++) {
			// make request to params[x]

			publishProgress(x);
		}
		return result;
	}

	protected void onProgressUpdate(Integer progress) {
		// update progress bar
	}

	protected void onPostExecute(String result) {
		// display result to user
	}
}

There is a lot going on in here so lets break it down. AsyncTask takes in three generic types. The first represents the input parameter type. For this example we are taking in URL objects because we are contacting a webservice. This will allow our task to contact multiple URLs from one thread (saving system resources). The second generic type represents the progress type. I chose an integer so I can display a fraction (4/10 sites contacted) or something like that. The third type represents the result type. Chances are when you contact a webservice, it will return JSON or XML. I chose String so I can put the result into that String and then parse it.

Here is a rundown of some of the methods you can override:

onPreExecute is called on the main thread before doInBackground is called. This is where you will initiate any progress indicators (such as progress bars).

doInBackground is called on a background thread and is where you will do the heavy lifting. This is where you do network communication, or heavy data work.

onProgressUpdate is called on the main thread whenever doInBackground calls updateProgress. This is where you will update the user on the progress of your background task. You might display a percent, or update a progress bar, or something else.

onPostExecute is called on the main thread after doInBackground returns. This is where you will remove progress indicators from the interface and present the updated information to the user.

Canceling a Task

It is important that your AsyncTask be capable of being canceled at any time. This will prevent your Task from preventing your app from closing in a timely fashion. To do this you will need to implement onCancel and you will need to regularly check isCancelled in doInBackground. Once cancel() is called, isCancelled will return true. Once true, doInBackground should return. If cancel() has been called, onCancel will be called instead of onPostExecute. This is an opportunity for you to clean up, and update your interface.

Using your custom AsyncTask

Once you have implemented your task, using it is very simple:

URL url1, url2, url3;
url1 = new URL(“http://www.something.com”);
url2 = new URL(“http://www.42.net”);
url3 = new URL(“http://www.yourmom.com”);

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

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: