Nov 27, 2012

f Comment

Android How to Make Threads Pass Data to Each Other?

Amazon First of all according to http://developer.android.com/guide/components/processes-and-threads.html:

The Andoid UI toolkit is not thread-safe. So, you must not manipulate your UI from a worker thread—you must do all manipulation to your user interface from the UI thread. Thus, there are simply two rules to Android's single thread model:

Do not block the UI thread
Do not access the Android UI toolkit from outside the UI thread

Therefore you should uphold this principle religiously. When we create a new thread we CANNOT update UI in that worker thread. Then how do I use the result of running a worker thread (or a child thread or a background thread) to update UI appropriately? In other words what's the proper way for a thread to communicate with another thread?

If you want to know how to make listener callback update UI read Android How to Make Listener or Receiver Callback Method Update UI?
Solution
There are several solutions, but I find using Handler and Message the simplest among all. In the following example you can see how the main thread creates a worker thread, and how the two threads pass data to each other.
public class MainActivity extends Activity {
...
Handler mHandler;
...
@Override
public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 ...
 mHandler = new Handler() {
  public void handleMessage(Message msg) {
   Log.v("TAG","Received a message from worker thread!");
  }
 };

}
...
public void mainButtonsOnclick(View v){
 TestThread tt = new TestThread();
 Thread ttt = new Thread(tt);
 ttt.start();

 Message.obtain(tt.getHandler(), 1, null).sendToTarget();

 // remember to kill the thread when it's no longer needed
}
...
private class TestThread implements Runnable {
 public Handler mHandler2 = new Handler() {
  public void handleMessage(Message msg) {
   Log.v("TAG","Received a message from main thread!");
  }
 };

 public Handler getHandler(){
  return mHandler2;
 }

 public void run() {
  Message.obtain(mHandler, 1, null).sendToTarget();
 }
}
...
The 3rd parameter of Message.obtain() can be a reference to any complicated data object, in which case handleMessage()'s parameter will contain that object so you can update UI or do whatever you want after you read the data passed from the worker thread. For example suppose you have the following code in TestThread::run:

Location location = new Location(...)
Message.obtain(mHandler, 1, location).sendToTarget();

And the following code in MainActivity's mHandler::handleMessage:

Location currentLocation = (Location) msg.obj;
Now currentLocation is the Location object passed by the worker thread.

The easiest way is make worker thread's class local in main activity. If you create a separate class for the thread you'll need to pass the main thread's handler as a parameter to the worker thread during the initialization of worker thread so that the worker thread will have the reference to the main thread's handler.

I've tried having more than one handler and it works in my application. However there's really no reason for doing so because you can distinguish among different types of messages via the "what" parameter in Message.obtain() method.
What if I just want to update UI in the worker thread?
Then you can just use handler's post() method like the following:
...
Thread workerThread = new Thread() {
 public void run () {
  ...
  handler.post(new Runnable() {
   @Override
   public void run() {
    // Update your app's UI
    updateUI();
   }
  });
 }
};
workerThread .start();
...
Easy right?

If you have any questions let me know and I will do my best to help you!


Please leave a comment here!
One Minute Information - by Michael Wen
ADVERTISING WITH US - Direct your advertising requests to Michael