Thursday, 21 November 2013

AsyncTask

Smart phones are great, they are like having a mini computer in your pocket. Smart phones suck, they are like having a mini computer in your pocket. You don't just pick up the phone and dial the number of the person with which you want to converse. First you must boot up the phone, find and then launch your telephone application, search for your friend's name, then within that entry you must choose with of their phone numbers you want to call. A nightmare. The last thing that you want within this process are applications that are laggy and do not respond to user input. Applications need to be snappy. And that's where multi-threading comes in to save the day.

When a process is created for your application, its main thread (aka GUI thread) is dedicated to running a message queue that takes care of managing the top-level application objects (activities, broadcast receivers, etc) and any windows they create. Only this thread can safely manipulate GUI objects and their state.
If you have to do some lengthy processing (such as complicated math, DB requests, SD card requests, network requests) then you should create a second thread (aka worker thread) to accomplish this work so that the initial thread remains snappy and responsive. However, remember that the worker thread can not update GUI objects. You can create your own threads, and communicate back with the main application (so that it may update GUI objects) thread through a Handler, as will be explained later on.
The simplest way to create a second thread is to use the android.os.AsyncTask

AsyncTask 
AsyncTask will create a worker thread for you and will also take care of the implementation details of communicating between your worker thread and your main thread. All you have to do is fill in the methods with your own code. Simple as pie.

The easiest way to use AsyncTask is as a private anonymous class within your Activity class. This will give you easy access to your Activity's member variables and any other resource you may need. You declare your new AsyncTask class like this :

private class LoadMatchDataAsyncTask extends AsyncTask<Void, Void, Void> {

As you can see AsyncTask is a templated class which receives three types. In this example I have simply used three Voids. These types are used for input values, updates and return values respectively. I personally find it more convenient to use the class' constructor for input values.

public LoadMatchDataAsyncTask(long playerId, long matchId) {
   mPlayerId = playerId;
   mMatchId = matchId;
}

But even this approach may be superfluous if you create your class as a private anonymous class.

The basic methods that you will want to override are

protected void onPreExecute()
protected Void doInBackground(Void...args)
protected void onProgressUpdate(Void... values)
protected void onPostExecute(Void return)

The onPreExecute(), onProgressUpdate() and onPostExecute() methods are executed within the context of your main thread and therefore allow you to update the UI. Such as putting up a progress dialog, setting text values and so on. The doInBackground() method is executed within the context of a worker thread that the AsyncTask class will create for you; this is where you will do all your lengthy processing. Inside of the doInBackground() method is also where you will make calls to publishProgress() in order to update your GUI to keep the user notified of what is going on. There are a few more methods that you may override, such as onCancel() which you will find in the documentation for AsyncTask.

To start your thread using the technique shown above, instantiate it and call execute(). In our example we declared no input type (Void) so the execute() method has no arguments.

new LoadMatchDataAsyncTask().execute();

The following graphic shows in which thread each method is run, as well as when the methods are called in relation to each other. Notice that in this graphic I have used three distinct types for the input, update and return parameters to make it easier for you to see where there are used.


As per the AsyncTask documentation there are a few rules that must be followed for this class to work properly
  • The task instance must be created on the UI thread.


Thread and Handler
The second way to create a thread in your code is to use java.lang.Thread to perform your background processing and an android.os.Handler to communicate back to your GUI thread. This is what AsyncTask does, but implementing it yourself gives you more freedom and control of your thread's execution.
First off, the Thread. Again we will implement our Thread as an anonymous class for simplicity. With the Thread class you must override the run() method, and this is where you will put your long running code.

Thread longRunningCode = new Thread() {
   @Override
   public void run() {
      // Count one BILLION dollars.
   }
};

longRunningCode.start();

And that's it. You now have a new thread counting up your ransom money. Of course your stand alone thread can't communicate with the user to update a progress dialog or anything of the sort. And of course like anything that gives you more control and power, it's as simple as pi [sic].

The way to communicate back to the GUI thread is through the usage of a Handler object.

When you instantiate a Handler it is automatically attached to the message queue belonging to the thread in which it is created. So if you want to communicate from a worker thread to a GUI thread you must instantiate a Handler in the GUI thread and then access it from the worker thread.

mHandler = new Handler();

The communication is done via posting a Runnable or sending a Message. A Runnable is a snippet of code that can be added to the Handler's message queue and then processed when appropriate.

Runnable mUpdateProgressBar = new Runnable () {
   public void run() {
      progressBar.setProgress(progressPercent);
   }
};

This technique will allow us to update the GUI object progressBar

Thread longRunningCode = new Thread() {
   @Override
   public void run() {
      // Count one BILLION dollars.

      // Display update in GUI thread
      mHandler.post( mUpdateProgressBar);
   }
};

As this point our AsyncTask example and our Thread/Handler example have the same functionality: a piece of long running code, and timely updates to the GUI. However the Thread class and the Handler class both have more tricks up their sleeves.



The Thread Class
Threads are a very powerful tool, and in Ben's famous words: “with great power comes great responsibility.”
The Thread class has many public methods, some of the more interesting are:
dumpStack() which prints out the current stack for this thread.
GetAllStackTraces() to retrieve the stack traces for all the currently live threads.
GetState which returns the current state of the thread
SetName which names the thread (so you can easily find it in DDMS)
setPriority()
sleep()

There are also many methods used for synchronization which is beyond the scope of this article.

The Handler class
As previously mentioned the handler class is bound to the message queue of the thread in which it was instantiated. This allows for much more than just posting a Runnable to the queue. With the Handler class you can also handle the messages which are sent to the thread by overriding the handleMessage(Message msg) method. Allowing you to send specialized messages from the worker thread and processing them within the main thread as you wish.

You also have control as to where your Messages and/or Runnables will be posted within the message queue using methods such as postAtFrontOfQueue(), postAtTime() and postDelayed(). These methods can help you design applications that can poll a network resource at a specific time, or wait an amount of time before launching your operation.

So which technique should I use?
As always, then answer to that question is: it depends. If you are new to threading, you will probably want to stick to AsyncTask for a little bit, just to get a better grasp of what's involved. In all my research I did not see an advantage for AsyncTask over Thread except for the fact that it is easier to code. However, after viewing the code for AsyncTask, there is no downside to using AsyncTask, there are no expensive lookups or a pile of conditionals. After that, it all depends on the job, and your context. For easy jobs in an application that is not very resource hungry you will want to go with AsyncTask. But if you require any kind of specialized processing you are going to want to get accustomed to using bare bones Java threading.