Android – Thread Messaging

16May09

Android provides Handler and Looper for threads to communication with each other. For example, a child thread is launched to create an image from the web. After it is done, it notifies the main thread (or the UI thread) by sending a message using the handler that’s bound to the main thread’s message queue. The data produced by the child thread can also be included in the message. I often use this pattern if I want the main thread to update the UI with the data produced by the child thread (you probably already know why if you have been playing with threads in Android).

When a Handler is created, it’s bound to the message queue of the thread that created it. If you create it in the main thread, you don’t need any extra code to loop the message queue for the main thread since it’s already been started when you run your application. However, if you are creating a Handler in a child thread, you need to initialize the thread to listen to its message queue before creating the Handler.

For example:

class ChildThread extends Thread {

    public void run() {

        /*
         * You have to prepare the looper before creating the handler.
         */
        Looper.prepare();

        /*
         * Create the child handler on the child thread so it is bound to the
         * child thread's message queue.
         */
        mChildHandler = new Handler() {

            public void handleMessage(Message msg) {

                /*
                 * Do some expensive operations there.
                 */
            }
        };

        /*
         * Start looping the message queue of this thread.
         */
        Looper.loop();
    }
}

Whenever the Handler receives a message, it would run the handleMessage(…). You can do some expensive operations in there. For example, you need to constantly send some data to the server. It probably would be more efficient if you have a thread listening for the messages to do the job instead of creating and running a new thread each time you need to do so.

If you are done with the looper, don’t forget to stop it by using its quit() method. For example:

mChildHandler.getLooper().quit();

Here is an example of creating a two-way communication between the main thread and a child thread:

package sample.thread.messaging;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

/**
 * @author davidkuo
 *
 */
public class ThreadMessaging extends Activity {

    private static final String TAG = "ThreadMessaging";
    private TextView mTextView;
    private Handler mMainHandler, mChildHandler;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mTextView = (TextView)findViewById(R.id.text);

        /*
         * Create the main handler on the main thread so it is bound to the main
         * thread's message queue.
         */
        mMainHandler = new Handler() {

            public void handleMessage(Message msg) {

                Log.i(TAG, "Got an incoming message from the child thread - "  + (String)msg.obj);

                /*
                 * Handle the message coming from the child thread.
                 */
                mTextView.setText(mTextView.getText() + (String)msg.obj + "\n");
            }
        };

        /*
         * Start the child thread.
         */
        new ChildThread().start();

        Log.i(TAG, "Main handler is bound to - " + mMainHandler.getLooper().getThread().getName());

        Button button = (Button)findViewById(R.id.button);
        button.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {

                /*
                 * We cannot guarantee that the mChildHandler is created
                 * in the child thread by the time the user clicks the button.
                 */
                if (mChildHandler != null) {

                    /*
                     * Send a message to the child thread.
                     */
                    Message msg = mChildHandler.obtainMessage();
                    msg.obj = mMainHandler.getLooper().getThread().getName() + " says Hello";
                    mChildHandler.sendMessage(msg);
                    Log.i(TAG, "Send a message to the child thread - " + (String)msg.obj);
                }
            }
        });
    }

    @Override
    protected void onDestroy() {

        Log.i(TAG, "Stop looping the child thread's message queue");

        /*
         * Remember to stop the looper
         */
        mChildHandler.getLooper().quit();

        super.onDestroy();
    }

    class ChildThread extends Thread {

        private static final String INNER_TAG = "ChildThread";

        public void run() {

            this.setName("child");

            /*
             * You have to prepare the looper before creating the handler.
             */
            Looper.prepare();

            /*
             * Create the child handler on the child thread so it is bound to the
             * child thread's message queue.
             */
            mChildHandler = new Handler() {

                public void handleMessage(Message msg) {

                    Log.i(INNER_TAG, "Got an incoming message from the main thread - " + (String)msg.obj);

                    /*
                     * Do some expensive operation there. For example, you need
                     * to constantly send some data to the server.
                     */
                    try {

                        /*
                         * Mocking an expensive operation. It takes 100 ms to
                         * complete.
                         */
                        sleep(100);

                        /*
                         * Send the processing result back to the main thread.
                         */
                        Message toMain = mMainHandler.obtainMessage();
                        toMain.obj = "This is " + this.getLooper().getThread().getName() +
                            ".  Did you send me \"" + (String)msg.obj + "\"?";
                        mMainHandler.sendMessage(toMain);
                        Log.i(INNER_TAG, "Send a message to the main thread - " + (String)toMain.obj);

                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            };

            Log.i(INNER_TAG, "Child handler is bound to - " + mChildHandler.getLooper().getThread().getName());

            /*
             * Start looping the message queue of this thread.
             */
            Looper.loop();
        }
    }
}

You can download the complete Eclipse project from here.



34 Responses to “Android – Thread Messaging”

  1. 1 Kiran

    Such a nice example explaining Android’s Handler and Looper concepts.
    Please send the source code of above mentioned example, this will be helpful for us.

    • 2 davidkuo

      Thanks. I’ve posted the complete example at the end. You just need to copy-past to your android project.

  2. 3 Dan Liew

    Hey thanks! These examples were really useful. Examples like these would be good on the Android Dev site.

    Just a small note in your first example you don’t declare mMainHandle

    I assume in onCreate() you have
    mMainHandle = new Handler();

    • 4 davidkuo

      Thank you for pointing it out. I’ve modified it and please see the complete example at the end.

  3. 5 Kiran

    HI Devid,
    Thanks for the reply. This is Kiran here. Sorry to say that, still I did not see the link to download the same code. If you don mind, can you please send me zipped copy the same code or exact link to download the code..

  4. 7 Kiran

    Thanks Devid..

  5. 8 Vikrant Singh

    Thank you for the awesome post.

  6. 9 QtCoder

    Thanks for this simple and easy to understand writeup.

  7. 10 JohnDroid

    Wow so easy to understand. Thanks for sharing!

  8. 11 vamshi

    A very good tutorial…thanks a lot i spent a good 3 hours for a tutorial like this…..and i have few other doubts in android is it ok if i post it here???

  9. 13 vamshi

    iam working on an android project where the activity should take the co ordinates from the gps device in the mobile phone and do the background calculations and update the ui…the code that i written creates a seperate thread sleeps for a specific period time before extracting the co ordinates and performing the operations…here the CustomerList Distance FareDistance GpsReciever are the static classes from which the UI thread takes data and updates it.

    import value.CustomerList;
    import value.Distance;
    import value.FareDistance;
    import value.GpsReciever;

    import android.app.Activity;
    import android.content.Context;
    import android.content.Intent;
    import android.location.LocationManager;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Looper;
    import android.os.Message;

    import android.util.Log;
    import android.view.View;
    import android.widget.CheckBox;
    import android.widget.TextView;
    import android.widget.Toast;

    public class Meter extends Activity {

    private static final int RESULT_GOOD = 2;

    private TextView customerid;
    private TextView totaldistance;
    private TextView totalamount;

    private LocationManager locationmanager;

    private CheckBox serververified;

    private static Boolean click = false;

    private GpsReciever gpsreciever;
    private CustomerList customerlist;
    private FareDistance faredistance;
    private Distance distance;

    public Handler handler = new Handler() {

    —->>> after getting the message object from the handler and calling it…my code fails to come here for the updation of the ui to work…all the background processes are working fine….<<<—
    public void handlemessage(Message msg) {
    if (click) {
    System.out.println("in handle msgs");
    /* CODE TO UPDATE THE TEXT VIEWS */
    totaldistance.setText(faredistance.getdistance());
    totalamount.setText(faredistance.getamount());
    } else {
    /* END THE THREAD */
    Intent temp = new Intent();
    setResult(RESULT_GOOD, temp);
    finish();
    }
    }
    };

    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.meter);
    customerid = (TextView) findViewById(R.id.TextView02);
    totaldistance = (TextView) findViewById(R.id.TextView04);
    totalamount = (TextView) findViewById(R.id.TextView05);
    totalamount.setVisibility(4);
    serververified = (CheckBox) findViewById(R.id.CheckBox01);
    locationmanager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

    gpsreciever = GpsReciever.getInstance();
    gpsreciever.setlocationmanager(locationmanager);
    faredistance = FareDistance.getInstance();
    customerlist = CustomerList.getInstance();
    distance = Distance.getInstance();

    String str = String.valueOf(customerlist.getcustomerid());
    customerid.setText(str);
    totaldistance.setText("000.0");

    }

    public void onclickmeter(View view) {

    serververified.setVisibility(4);
    totalamount.setVisibility(0);
    click = (!click);
    System.out.println(click);

    Thread background = new Thread(new Runnable() {
    public void run() {
    try {

    Thread.sleep(5000);
    /* ALL THE BACKGROUND PROCESSES ARE DONE HERE */ handler.sendMessage(handler.obtainMessage());

    } catch (Throwable t) {
    System.out.println("error");
    }
    }
    });
    background.start();

    }
    }

    Any help will be greatly appreciated…thanks in advance

  10. 15 Szabolcs Balogh

    Hy!

    It is a great tutorial about how to communicate between threads. Thank you for it…
    I hope you can help me. I’m trying to use inter thread communication and network socket (client), but I don’t how it is possible, because both Looper and socket (when waiting for message from server) are blocking. Do you have an advice how can I mix these 2 things?

    Thank you

    PS. Sorry for my english.

    • 16 davidkuo

      Please check my YaMovies post and download its sample program. It shows how to create another thread to get the RSS feed from the server. It uses HTTP connection instead of sockets, but I think the concept is the same. Thanks.

  11. Hello everybody

    If you have an expirience with making graphic to web on-line shop please let me know.
    I’m looking for somebady hwo can create and implement graphics to on-line shop.

    Best Regards
    Kultinaria

  12. A good example on how to use handler and looper. Explain with a good naming convention too.. I like this post

  13. 20 Sudhakar Chavali

    Hi David

    I am facing some kind of problem in handling the message queues

    For your understanding here is the skeleton of my classes. Please let me know where exactly I am creating mistakes.

    My Thread Class
    =============

    public class HttpHandler extends Thread
    {
    Vector request=new Vector();
    public void postRequest(Object o){
    {
    requests.add(o);
    }
    public void run(){
    {
    while(true){
    if(requests.size()>0){
    Object o requests.elementAt(0);
    int response= postObjectTo(myURL, o);
    if(response==200){
    }
    else{
    Looper.prepare();
    Handler handler=new Handler();
    handler.post(new Runnable(){
    public void run(){
    //show dialog

    // quit the looper.
    }
    });
    }
    }
    }
    }
    }

    Now my problem is if I try to quit the looper I am getting exception. If I don’t do that I am unable to process new request objects. How to manage that?

    • 21 davidkuo

      Since you’re creating the handler in a child thread, you need to call Looper.loop(); to loop the message. If the handler is created on the main (UI) thread, looping is done for you automatically. Hope this will help.

      Also, I’m not sure if this would work (showing dialog part):

      handler.post(new Runnable(){
      public void run(){
      //show dialog

      // quit the looper.
      }

  14. 22 Shahzad

    I have defined two Handlers MainHandler and Child Handler

    My Thread XYZ is able to send data to main via MainHandler but I also want to communicate to Thread from Main

    the problem faced by me is that my Thread has a infinite loop which is in its run() routine
    how Can I have an infinite loop inside my Thread and also transfer data to it via main code

    public class XYZ extends Thread
    {
    @Override
    public void run()
    {
    while(true)
    {
    //communicate with the server and pass the data to main via MainHandler.sendMessage(myData)
    //Thread.sleep(defined_Interval);
    ………
    }
    }
    }

    I tried by adding
    Looper.prepare();
    ChildHandler = new Handler() {
    public void handleMessage(Message msg)
    {
    Log.i(“TCP”, “Got an incoming message from the main thread – ” + (String)msg.obj);
    }
    };
    Looper.loop();
    while(true)
    {
    //my code
    }

    but my part of code doesnt work and when I try this

    Looper.prepare();
    ChildHandler = new Handler() {
    public void handleMessage(Message msg)
    {
    Log.i(“TCP”, “Got an incoming message from the main thread – ” + (String)msg.obj);
    }
    };

    while(true)
    {
    //my code
    }
    Looper.loop();

    it says that Unreachable code at Looper.Loop(); line

    • 23 davidkuo

      Why don’t you separate the infinite loop and the child handler into 2 thread objects. This way, only the thread object that contains the child handler needs to call the Looper.loop().

  15. Fine app for android thanks for the tip I am already experimenting in my android and perfect
    a work in very nice.

  16. 25 mack

    Hi David,

    You are great. Kudos to david for providing such a excellent use of handler and looper.

    I am very happy and want to say thanks from my bottom of heart.

    Thanks,

  17. 27 stam

    Hi,
    The sample is really helpful, thank you for that.
    BTW, when I’m trying to debug this sample the line

    “Log.i(INNER_TAG, “Send a message to the main thread – ” + (String)toMain.obj);”

    prints null instead of data of toMain.obj. Somehow toMain.obj is started to be null after message sent to queue.

    Please your help & clarifications reg. this issue.
    Thanks,
    Alex

    • 28 davidkuo

      Not sure what’s wrong with it. It works fine in my environment. Try to run it using Android 1.6. When you click on the “Communicate with the child thread” button, do you see the output on the screen?

  18. 29 stam

    David,
    Thank you for your prompt reply.
    I tried with Android 1.6 and got the same result.
    Actually the messages get the relevant queues and on the screen “The child.Did you send me “main says Hello?”” displayed correctly.
    The problem is that the message started to be null after a it was sent by
    sendMessage(msg) function.

    It’s easily to simulate by putting sleep after sendMessage function:

    mMainHandler.sendMessage(toMain);
    Thread.sleep(3000); // 3 sec
    Log.i(INNER_TAG, “Send a message to the main thread – ” + (String)toMain.obj);

    and LogCat prints
    02-28 19:52:06.383: I/ChildThread(384): Send a message to the main thread – null

    • 30 davidkuo

      Why don’t you cache it:

      String message = (String)toMain.obj;

      mMainHandler.sendMessage(toMain);
      Thread.sleep(3000); // 3 sec
      Log.i(INNER_TAG, “Send a message to the main thread – ” + message);

      The toMain was probably removed or cleared after the other thread has received it.

  19. 31 stam

    Now I’ll do that. BTW, it’s not declared in any documentation.

    Another strange thing is that msg sent to child thread is not cleared:

    mChildHandler.sendMessage(msg)
    Log.i(TAG, “Send a message to the child thread – ” + (String)msg.obj); // prints correctly

    I’m just trying to find a logical explanation.

  20. 32 stam

    Another question that I don’t know how to figure out is how to cash all the message.

    This code is not working and temp is also null after sendMessage executed.

    //——————————————————
    Message temp = Message.obtain(); // or mMainHandler.obtainMessage();
    temp.copyFrom(toMain);
    //——————————————————
    mChildHandler.sendMessage(msg)

    I suppose it’s because of copyFrom does shallow copy.

    I would appreciate your advice reg. this matter.
    Thanks

  21. 33 Francesco

    Thank you! finally a great example for Threads!!


  1. 1 liehacker (남궁혁) » 안드로이드 UI 업데이트, 쓰레드 Handler, 라이프싸이클 lifecycle

Leave a reply to stam Cancel reply