Sharing the Code

Programming stuff that might be useful to others

Threads and handlers in Android

On iOS you can get away with not being too concerned about the responsiveness of the UI when doing things like saving to the database but on Android the slugishness is noticeable. This is the scenaro – the user taps on a UI control which starts an operation that takes a small but noticeable time to complete – you are basically trying to avoid a non-responsive UI. If the operation is fairly short you can get away with using a Handler. This allows you access to the main UI thread’s message queue. If the operation is a bit longer, say a second or more you would want to use a thread.

In the following piece of code I have a click listener on a checkbox in a list. When the user taps on the checkbox it saves the new state to the database. I’ve put the database operation in a Runnable and passed it to Handler.post() so that the checkbox updates it’s visual state before saving to the database, otherwise there would be a delay in the checkbox’s tick appearing or disappearing.

[sourcecode language=”java”]
private Handler mHandler=new Handler();

private final View.OnClickListener mCheckBoxClickListener=new View.OnClickListener(){
public void onClick(View view){
final CheckBox checkBox=(CheckBox)view;
mHandler.post(new Runnable(){
public void run(){
//e.g. save to the database
}
}
}
}
[/sourcecode]

In another scenaro I have an operation that takes a little bit longer to complete. In the following piece of code, I first show a progress dialog and then start the long operation in a thread. When it’s finished it sends a message to the main UI thread which updates the UI and hides the progress dialog.

[sourcecode language=”java”]
private static final int SOME_OPERATION=1;

private void doLongOperation(){
showProgressDialog();
new Thread(new Runnable(){
public void run(){
//some long operation
mHandler.sendMessage(Message.obtain(mHandler, SOME_OPERATION));
}
}).start();
}

private Handler mHandler=new Handler(){
@Override
public void handleMessage(Message message){
switch (message.what){
case SOME_OPERATION:
//update UI
hideProgressDialog();
break;
}
}
}
[/sourcecode]

Android has a class called AsyncTask for this particular scenaro i.e. running a task in the background and then updating the UI.

There is a situation where your activity will be destroyed and recreated while your asynchronous task is running i.e. when you rotate the device. The solution is to keep a reference to the thread in a static member. When the activity is first created it will create the thread. When the activity is subsequently destroyed the thread’s handle property is set to null so it doesn’t try and send a message to an invalid handler. When the activity is recreated the new handler is passed to the thread if it’s still alive.

[sourcecode language=”java”]
private static MyThread sThread;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState==null){
showProgressDialog();
sThread=new MyThread(mHandler);
sThread.start();
}
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState){
super.onRestoreInstanceState(savedInstanceState);
if (sThread.isAlive()){
showProgressDialog();
sThread.setHandler(mHandler);
}
}

@Override
protected void onDestroy(){
super.onDestroy();
if (sThread.isAlive()){
sThread.setHandler(null);
hideProgressDialog();
}
}

private Handler mHandler=new Handler(){
@Override
public void handleMessage(Message message){
//update UI
hideProgressDialog();
}
}

private class MyThread extends Thread{
private Handler mHandler;

public MyThread(Handler handler){
super();
mHandler=handler;
}

@Override
public void run(){
//some long operation
if (mHandler!=null)
mHandler.sendEmptyMessage(0);
}

public void setHandler(Handler handler){
mHandler=handler;
}
}
[/sourcecode]

Comments are closed