Threads, handlers and AsyncTask: efficient
asynchronous programming in Android
When creating Android applications
you sometimes need to fetch data from servers, create game event loops or get
information from web sites. Since Java’s IO operations are blocking,
there is a risk of freezing the application if you try to do these time
consuming operations directly in the UI thread. This can result in getting an ANR, which is short for Application Not Responding,
a dialog that appears after the application has been frozen for 5 seconds and
where the user has the option to kill the entire application.
An obvious solution is to run these
operations in a separate thread but when you need to update the UI you can not
do this from any other thread then the UI thread or you will run into problems.
This is because the UI thread is not thread-safe.
Android has two main rules for
handling threads:
- Do not block the UI thread
- Do not access the Android UI toolkit from outside the UI thread
These two rules can be conflicting
when programming asynchronously, but there are several ways to make sure that
these rules are always followed:
- Schedule to the UI thread using Android built-in methods
- Asynchronous methods
- AsyncTask is a utility class provided by Android which handles threading for you. Easy to use when a large amount of data needs to be fetched and then displayed in the UI.
- Explicit threading
- Plain Java threads that preforms time consuming tasks and then by using a Handler schedule the task to update the UI to the UI thread.
Schedule
to the UI thread using Android built-in methods
There are three built-in methods in
Android that can handle the situation when one of your Activity classes are run
on or called from a different thread. We can then schedule the UI updates to be
run on the UI thread with these three methods below. The Activity or View then
works as a handler (more on handlers
below) and schedules your runnable to the UI thread:
- Activity.runOnUiThread(Runnable)
- View.post(Runnable)
- View.postDelayed(Runnable, long) //(long = time to scheduling)
Example:
Activity.runOnUiThread(new
Runnable() {
public void run() {
//Update UI
}
});
Asynchronous
methods – AsyncTask
AsyncTask can be useful in
situations when there is a need for getting something from a server or a web
page and then show it in the UI as soon as it is finished. When using AsyncTask
you usually create an internal class which extends AsyncTask. This class
implements mainly two methods, doInBackground and onPostExecute, there are two
more that can be implemented for when something needs to be done before the
doInBackground method or during its execution as seen in the example below. The
three generic arguments for AsyncTask can be changed to whatever is needed for
the situation for more details see example below.
Example:
class
Async extends AsyncTask{
//Run on UI thread
@Override
protected void onPreExecute(){}
//Run in separate thread
@Override
protected Z doInBackground(X input){
//Do task, like getting info from
web
return result;
}
//Run on UI thread
@Override
protected void onProgressUpdate(Y y){}
//Run on UI thread
@Override
protected void onPostExecute(Z result){
//Do something with data like
update UI
}
}
Async
task = new Async();
task.execute(X
input);
The method doInBackground is the
only asynchronous method, the other three methods are run on the UI thread and
can therefore update the UI. AsyncTask is an easy way for you to do time
consuming operations in the background and updating the UI. The big advantage
is that you don’t need to handle the threads yourself Android through Java does
this for you.
Explicit
threading
By using the Java’s Thread
and Runnable
with Android’s Handler, a simple loop can be created and used for continuously
update a process bar, run a game loop or get data from a server without
blocking the UI thread.
Handler
Handler
is a class from the Android library, it can be used in two main
ways: it can handle messages and schedule runnables to the UI thread or it can
do the same but schedule them on a different thread. The handler gets bound to
the thread in which it is created so if it is created in the UI thread it can
be used to schedule tasks for the UI thread within another thread. Examples
follow below:
Example on how to create a thread
safe loop run in a different thread then the UI thread:
//Create
handler in the thread it should be associated with
//in
this case the UI thread
final
Handler handler = new Handler();
Runnable
runnable = new Runnable() {
public void run() {
while(running){
//Do time consuming stuff
//The handler schedules
the new runnable on the UI thread
handler.post(new Runnable()
{
@Override
public void run()
{
//Update
UI
}
});
//Add some downtime
try {
Thread.sleep(100);
}catch (InterruptedException
e) {
e.printStackTrace();
}
}
}
};
new
Thread(runnable).start();
Example on how to create an
asynchronous thread with similar abilities to AsyncTask, the advantage with
this loops is that you can create more than one asynchronous method and it can
easily be turned into a loop by inserting a while loop. Everything concerning
updating the UI is done in the runnable that the handler, in turn, schedules
onto the UI thread:
//Create
Handler bound to the UI thread
Handler
handler = new Handler();
static
public class MyThread extends Thread {
@Override
public void run() {
//Do stuff that takes time
//To be able to update the UI we
have to post
//the runnable onto the UI thread
handler.post(new MyRunnable());
}
}
static
public class MyRunnable implements Runnable {
public void run() {
//Update the UI
}
}
MyThread
thread = new MyThread();
thread.start();
Final
thoughts
There are several ways to deal with
the issue of updating the UI from a different thread. These examples would
solve most of the problems encountered (with a little modification to the code)
but I am sure that there are situations where special solutions are needed.
However, do keep in mind that the above examples is only needed when updating
the UI from any other thread then the UI thread. If you only need a thread
doing operations asynchronously that doesn’t involve the UI you can always use
normal Java threading.
Comments
Post a Comment