In the previous article in this series we looked at the UI thread and explored the reason why it is important that we keep any slow, intensive, or blocking tasks off the UI thread. In this article we’ll begin exploring the tools available to help us to achieve that.
The simplest tool that we have have at our disposal is the humble Java thread. Running a task on a new Thread is really very simple:
[java] new Thread( new Runnable(){
@Override
public void run()
{
// Do something
}
} ).start();
[/java]
By simply putting our task in the run()
method of a Runnable we can execute it in a new thread which will die automatically when our task completes.
We can quickly encounter problems with this. Consider the following example:
[java] new Thread( new Runnable(){
@Override
public void run()
{
// Do something
TextView textView =
(TextView) findViewById( R.id.textview );
textView.setText( “Hello World” );
}
} ).start();
[/java]
We perform some non-trivial task, but once it’s complete we want to change the text in a TextView. On the face of it, it looks fine, but if we run this we’ll get a runtime exception thrown:
E/AndroidRuntime(9129): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
What this means is that if we want to modify any view (such as the TextView in our example) this must be performed on the thread that created the view – our old friend the UI thread. This can get somewhat confusing: we’re specifically trying to get stuff off of the UI thread, and here we find that we actually need to update our View objects on the UI thread. The temptation here is to simply switch everything back to the UI thread but, as we have already discussed, this is a really bad idea.
Fortunately, there are some mechanisms that we can use to execute code back on the UI thread. Activity has a method named runOnUiThread() which allows us to execute code specifically on the UI thread:
[java] new Thread( new Runnable(){
@Override
public void run()
{
// Do something
final TextView textView =
(TextView) findViewById( R.id.textview );
runOnUiThread( new Runnable()
{
@Override
public void run()
{
textView.setText( “Hello World” );
}
} );
}
} ).start();
[/java]
Once again we use a Runnable to wrap the code that we want to execute. Being Android, there is an alternate way of achieving the same result:
[java] new Thread( new Runnable(){
@Override
public void run()
{
final TextView textView =
(TextView) findViewById( R.id.textview );
textView.post( new Runnable()
{
@Override
public void run()
{
textView.setText( “Hello World” );
}
} );
}
} ).start();
[/java]
This is fairly similar except that we are using the post() method on our TextView instead of runOnUiThread() and is useful for cases where we have access to an individual View but not the Activity it resides in. Each View object has a message queue which is processed sequentially on the UI thread. post() allows us to add a new message to the message queue.
The message queue mechanism is implemented using a Handler object, and another way that we could implement things is by creating our own Handler instance which gets created on the UI thread, and we can then post messages to it which get executed on the thread upon which the Handler was created:
[java] final Handler handler = new Handler();new Thread( new Runnable()
{
@Override
public void run()
{
// Do something
final TextView textView =
(TextView) findViewById( R.id.textview );
handler.post( new Runnable()
{
@Override
public void run()
{
textView.setText( “Hello World” );
}
} );
}
} ).start();
[/java]
So, moving things off of the UI thread is relatively easy, as is moving things back on to the UI thread. However, if we have a long running task from which we want to periodically update the UI (for example updating a ProgressBar) means that we have to keep jumping to the UI thread to do this, and our code begins to get rather messy as a result. Android provides AsyncTask which can make our life much easier, and we’ll have a look at this in the next part of this series.
I haven’t released the source code for this article because the code snippets are actually self-contained, functional blocks that you can simply cut and paste from the article. I will release the source for later articles when the code spans multiple.
© 2012, Mark Allison. All rights reserved.
Copyright © 2012 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.
1 Comment