Thursday, February 17, 2011

Android : Passing data between main thread and worker threads.

There may be situations where you want to spawn a thread from your Activity or Service to handle long running (and may be blocking) tasks. In such cases, its sometimes necessary to pass data back and forth between the main thread and the worker thread(s). E.g. if the worker thread finishes a task and returns the result to the main activity to display the results OR you want to keep a worker thread around and ask it to switch between tasks depending on some message you pass to it.

In the past, I faced some problems understanding these concepts associated with different classes in android.os like the Handler, Looper, HandlerThread etc...

I'll try to explain these concepts in a simple language. Probably most of these explanations are from the developer documentation, but I thought consolidating these at one place may help to get a good picture.

Ok. So, when an application runs, it runs in a Main thread called as the UI thread. Any other thread can be created using the standard java.lang.Thread class. As I said in a typical situation you will spawn a thread, may be pass some data to it OR the thread may pass back some data to the Main thread from time to time as well as when its done executing.

Let us consider the task where we need to send data to a worker thread. So first, we create a worker thread.

STEP 1: Create a worker thread

class MyThread extends Thread {
    @Override
    public void run(){
    }
}

In our main thread...

MyThread mThread = new MyThread();
mThread.start();

When you have to pass any messages to a thread or get messages from a thread, the receiving thread needs a MessageQueue. By default, a thread created by using the java.lang.Thread class will not have a MessageQueue associated with it. Its just a plain old thread as in the Fig. 1 (Yes, I know. What an innovative diagram !! :D ).




Now, we need to attach a MessageQueue to our thread. The Looper class provides the method prepare() to create a message queue for a thread. We need to call this method from the receiving thread's run method.


STEP 2: Call the Looper methods


class MyThread extends Thread {
    @Override
    public void run(){
           Looper.prepare();
           Looper.loop();
    }
}



As you see, there is one more Looper method called in the code. This loop() method will start running the message loop for the current thread. In simple terms, it will start looking at the MessageQueue and processing the messages. This is how I interpret the Looper as in Fig. 2.



But, who sends the messages to the MessageQueue and how are these processed ? There is a class called the Handler. The Hander allows us to send and process Messages (as well as Runnable Objects) associated with the thread's MessageQueue. So, we need to create a Handler. It is important to note that the Handler is associated with the thread that creates it ! The Handler provides methods to handle (receive) Messages as well as send and schedule messages. For details, please refer to documentation.



STEP 3: Create a Handler to receive the Messages

class MyThread extends Thread {
    public Handler mHandler;

    @Override
    public void run(){
           Looper.prepare();

           mHandler = new Handler() {
                   public void handleMessage(Message msg) {
                       // Act on the message
                   }
           };
           Looper.loop();
    }
}

If you notice, this code is the same that is listed on the Looper documentation page here.  Few things to mention here are. The Handler is created in this thread, hence it is associated with the default Looper (read MessageQueue) in the current thread. There are constructors for the Handler that allow us to specify the Looper (again, read MessageQueue). This allows us to write a cleaner code by writing the Handler class separately and passing on a Looper (again, again, read MessageQueue) when the Handler is created. I'll get to this in a while. But as I have insisted, it is worth noting that whenever the developer documentation refers to a Looper, you can assume they are talking about a queue. I'm really not sure why they have surfaced the Looper class. It creates more confusion (at least for me). Also, when dealing with passing the messages, with this mechanism, we really need not care of the MessageQueue call. That is the reason I haven't linked it to the documentation. Anyways... things are what they are ! For me, I like to interpret this whole mechanism as depicted in Fig. 3.


Let me know if you like PAT or your way of viewing it !

So, now any other thread having the reference to mHandler will be able to call the send or post methods of the Handler class to send a Message (or a runnable object) to our thread. The code for sending message will look like:

Message msg = Message.obtain();
msg.obj =  // Some Arbitrary object
mHandler.sendMessage(msg);

Pretty simple yeah ! Btw, there are various methods to set/get data for the Message object which can be found in the developer documentation for the Message class.

Summary of Steps :
1. Create a Handler in the receiving thread [If it is the main thread, create one in the main thread]. By default the handler will be associated with the default queue (Looper).
2. So, if the receiving thread is created by using java.lang.Thread, then we need to call the Looper.prepare() and Looper.loop() in order to set up the message queue for the thread.
3.  In the sending thread, prepare a message object (or a Runnable object)
4. Get a reference to the Handler in the sending thread and call the send/post methods on it to send a message.

HandlerThread:
Since by default java.lang.Thread doesn't contain a message queue (Looper), Android provides a class called as the HandlerThread which already contains a message queue. The only difference in using the HandlerThread class over the method described above is that you need not call the Looper.* methods.

On creation of a HandlerThread, Android will create a thread containing the looper. So, in the main thread the code will look like:

HandlerThread myThread = new HandlerThread("Worker Thread");  
myThread.start(); 

We separately create a Handler as follows:

class MyHandler extends Handler { 
    public MyHandler(Looper myLooper) { 
        super(myLooper);
    }
    public void handleMessage(Message msg) { 
    }

Now in the main thread, we get the looper for the HandlerThread and pass it when we create the Handler as follows:

Looper mLooper = myThread.getLooper(); 
MyHandler mHandler = new MyHandler(mLooper); 

Whenever we want to send a message from the main thread, we do it in a similar fashion.

Message msg = mHandler.obtainMessage(); 


msg.obj =  // Some Arbitrary object
mHandler.sendMessage(msg); 


I like to visualize this as shown below in Fig. 4 where we write the Handler separately and then pass a looper to it on its creation.





28 comments:

  1. Thank you very much!
    Threads are one of throes things there doesn’t appear a lot of (helpful) information on and inter-tread communication is one of throes key things people assume you know.
    Anyway I’ve got a couple of quick questions I hope you can help me with.
    Firstly, at the foot of your post when you talk about the UI thread getting the looper for the worker thread you has the following code :-
    Looper mLooper = myThread.getLooper();
    MyHandler mHandler = new MyHandler(mServiceLooper);
    Should that be:
    Looper mLooper = myThread.getLooper();
    MyHandler mHandler = new MyHandler(mLooper);
    Or is mServiceLooper declared somewhere else and I’ve missed it?
    Secondly am I correct in assuming worker thread can talk to other worker threads (ones they start) in the same way?

    Thanks again Scott

    ReplyDelete
  2. @Scott Thanks for the comment.
    1. I'm sorry its a typo. Thanks for pointing it out.
    2. Yes, as long as the worker threads have access to the handlers of other threads, they can communicate and this is the preferred mechanism too.
    Hope this helps.

    ReplyDelete
  3. Now don't get me wrong, this is a good article, but I fear it unnecessarily confuses two separate ideas: 1) Threads and 2) the Looper/Handler/MessageQueue implementation build on TOP of Java threads. The presentation might be improved by separating these tow ideas.

    So, for example, is is simply not true to claim that "When you have to pass any messages to a thread or get messages from a thread, the receiving thread needs a MessageQueue." Why, the whole POINT of the distinction between 'threads' and 'processes' is that threads share address space (therefore global variables) while processes do not. So messages can be passed through globals.

    Now of course, globals introduce their own problems, and should be avoided anyway in Object Oriented Programming, whic is what we are usually trying to do in Java in the first place. But I have often seen Android programmers use shared variables like this for very simple message passing. The reader of this article should be prepared for seeing such things too. Even if the article does not recommend imitating such code.

    After all, only the very simplest message passing should be done with shared variables: the MessageQueue should be used for more complicated scenarios.

    ReplyDelete
  4. I hope I am not flooding you with too many comments, but it also occurs to me: no discussion of Threads and threading can be complete without mention of the classic problems of multi-threading, data races, deadlock and starvation. These are mentioned briefly and in slightly different language in Oracle's Java Tutorial (thread on concurrency), and also at http://www.cs.duke/edu/~chase/systems/concurrency.html.

    To be sure, most of these problems can be avoided by using the MessageQueue, but not all. If the programmer is not thinking about it, he can accidentally design a message-passing scheme that is still liable to deadlock, especially with multiple worker threads.

    The classics on these issues, by Birrell and Dijkstra, are still good reading, but their code samples all use pseudo-code based on ancient languages like Modula II and Algol60:( That is why I gave you the Duke University reference instead.

    ReplyDelete
  5. Question: in Step 2, you say, "In simple terms, it [the Looper] will start looking at the MessageQueue and processing the message". Then a little later you say about the Handler that "The Hander allows us to send and process Messages".

    But wait! Now we have message processing mentioned as happening in TWO different places. How can this be correct? Is there a difference between the 'processing' that takes place in the Looper, and that that takes place in the Handler methods?

    This was never clear in the online Android documentation either, so your readers will thank you even more than they already have if you can make it clear;)

    ReplyDelete
    Replies
    1. I guess that the handler's handleMessage will be invoked by the Looper on the receiver thread

      Delete
  6. Thank you for that.
    It was also helpful for me.

    ReplyDelete
  7. Do both the sender and receiver need loopers? Or just the receiver?

    Thanks,

    Chris.

    ReplyDelete
  8. @Chris, you'll need a Looper only retrieve (receive) messages

    ReplyDelete
  9. Great explanation!

    But what if you had an ArrayList that contains custom objects that you have to pass to the main thread?

    Let me give an example: you want to show a list of movies to the user, but this is kind of a big list so you'll use a thread to fetch and load the movies.
    step 1: address your handler to fetch the movies and make an arraylist of movies (an object that you made yourself, with title, cover, ...)
    step 2: returning this list to your UI-thread
    step 3: displaying your movies

    How would you return this list to your UI-thread? And how do you write your movie class? Do you just make a class with properties and no special interfaces to implement or do you have to implement Parcelable and methods or Serializable?

    Thank you in advance :-)
    Niels

    ReplyDelete
  10. @Niels, for such complex data, I would suggest you take a look at the REST API design pattern (http://www.google.com/events/io/2010/sessions/developing-RESTful-android-apps.html). This article is mainly for quick and short data. For a large amount of data like the ArrayList that you want, it would be advisable to cache the data. What if the main thread is stopped by the time the worker thread completes its task ? All the effort of fetching and loading the movies will go waste. You will have to redo everything which will be expensive !

    ReplyDelete
  11. Great explanation but I still need a little help to understand how to use this please.
    In step 3 the data has been passed to mHandler as 'msg'.
    'msg' is a variable in local class mHandler so does not have scope outside mHandler.
    So how do I use the data in 'msg' with the MyThread class?

    Thank you,
    Declan.

    ReplyDelete
  12. THANK YOU!!! I've been searching for some time for a good (in this case, great) explanation. Threads and message queue are finally clear to me. For everything else I can use android docs, but now I understand the principles...

    Cheers!
    Newman

    ReplyDelete
  13. Thank You, nice explanation. I have a very basic question here,
    Iam clear in sending message to the thread created by main, but how to communicate back results to main thread from child ?
    -regards,
    Manju

    ReplyDelete
    Replies
    1. Manja,

      I believe u need to have a separate msg q (read as Looper) and it's handler object in the main.

      --Guru

      Delete
  14. Excellent. Just what I was looking for.
    I wonder how this blog was hidden from me for so many days.

    ReplyDelete
  15. Excellent and extraordinary explanation on the concept of threads and loopers, i am really glad to bookmark this blog......:)

    ReplyDelete
  16. Nice Thread Tutorial, i am new in android , its help me a lot ...

    I have got some good links

    here
    at androidexample.com
    Thread_With_Handlers

    ReplyDelete
  17. Nice Thread Tutorial, i am new in android , its help me a lot ...

    I have got some good links

    here
    at androidexample.com
    Thread_With_Handlers

    ReplyDelete
  18. Nice Thread Tutorial, i am new in android , its help me a lot ...

    I have got some good links

    here
    at androidexample.com
    Thread_With_Handlers

    ReplyDelete
  19. Thanks for the posting very useful blog. There is a stack overflow post about an issue which can help developer also. Please check this URL http://stackoverflow.com/questions/4838207/how-to-create-a-looper-thread-then-send-it-a-message-immediately.

    ReplyDelete
  20. Thanks a lot for posting this post, Your post has always been an informative source for me.
    android training

    ReplyDelete
  21. I am reading your post from the beginning, it was so interesting to read & I feel thanks to you for posting such a good blog, keep updates regularly..
    Android Training Institute in Noida
    Dot Net Training Institute in Noida

    ReplyDelete


  22. Thanks for sharing this valuable information and we collected some information from this blog.
    Android Training in Noida

    ReplyDelete
  23. Thanks for writting such informative articles to help us Noobs :)

    ReplyDelete