Search code examples
androidmultithreadingandroid-handlerandroid-looper

Is a Handler a Thread or not, and what is the role of a Looper with Handlers and Threads?


Is a Handler a Thread or not? If yes, how can we update the UI from this Handler(thread)?

If we use the Looper concept, it may be possible. In this case, does it apply to any threads? I am very much confused about these Threads, Handlers and Loopers. Could anyone please explain them with an example? Is a Handler a Thread or not? If yes, how can we update the UI from this Handler(thread).

If we use the Looper concept, it may be possible, in this case does it apply to any threads? I am very much confused about this Thread, Handler and Looper. Could anyone please explain them with an example?


The question "What is the difference between a Thread and a Handler" is only about Handlers and Threads, but does not explain Loopers and their behavior. And the accepted answer says that "Handlers on the other hand are background threads that allow you to communicate with the UI thread (update the UI)", but according to the answer by "ben75" below, a Handler is not a Thread. Thus, I do not think this is a duplicate of that question.


Solution

  • premise : A Handler is not a Thread.

    A Looper is an Object associated with the Thread from which it is created. As you can guess by it's name a Looper is going to loop over something, but looping over what ? Over a message queue also associated with the same thread.

    Next question is: How can I put something in this message queue ?

    And here is the Handler. A Handler is always associated with a Looper (which one ? we will see it later). The Handler can play 2 roles (and that's maybe why it is confusing)

    First role of the Handler : you must use it to post messages to it's associated Looper (in fact to it's message queue). You can use one of the various Handler.sendMessage* (or Handler.post*) methods to do that. (and note the sendMessageDelayed/postDelayed methods allowing you to post a Message/Runnable to be handled in future)

    What is the Looper associated with a Handler ? Very easy : the Looper of the current Thread if you don't specify it; but you can use the constructor with a Looper : new Handler(Looper looper) and in this case the handler is associated with looper in argument.

    At this point, we know that :

    • a Looper is associated with one and only one Thread
    • a Looper loops over it's associated message queue
    • as a consequence : there is one message queue associated with one Thread (as soon as we have a Looper for the Thread)
    • a Handler is always associated with one Looper
    • a Handler can be used to post message to the message queue

    Now, let's see the second part : the message processing/message handling.

    First, let's look at the Looper looping over it's message queue.

    Is there is a message in the queue ? Yes (i.e. at some point, a Handler has posted it.) Is it time to handle this message (if it was posted with postDelayed) ? If not, wait a little. If it is time : let's dispatch this message.

    Remember that I told that the Handler have 2 roles... and here is the second role of the Handler : a Handler (as indicated by it's name) can handle messages. To be able to handle custom messages you must subclass the Handler class and implements the handleMessage(Message) method.

    So, the Looper will simply call the handleMessage of the Handler who posted the message and it's job (i.e. dispatching the messages) is finished (the Looper can move on to the next Message in the queue).

    At this point you may ask yourself : "OK I see the interest of delayed messages, but why should I use all this stuff for things to do immediatelly ?"

    Remember that the Looper is associated with one Thread and the handleMessage will be called in this Thread. On the other hand, the Handler.post* can be called from another thread. So this mechanism is also very convenient to schedule a job in thread X from thread Y. (particularly useful if the job is affecting the UI and MUST be run in the UI-Thread)

    Final note

    • UI-thread is a first class citizen :

    On Android, there is a main Looper associated with the main Thread (i.e. the UI-thread). You can get a reference to it with Looper.getMainLooper(), so you create a Handler associated with the main Looper with :

    Handler myHandler = new Handler(Looper.getMainLooper());
    

    and with that you can post a message from any thread to the UI-thread

    • Should you really use messages and subclassing Handler to use this ? No (not always)

    You don't always need to create message explicitly to use this mechanism. You can easily post a Runnable to a Handler and in this case you don't even need to override the handleMessage(Message) because the default implementation of the Handler will simply execute the Runnable (under the hood : a message is created with the Runnable associated to it)

    • Looper must be prepared (to receive messages)

    By default there is no Looper on every thread (by default, there is only a prepared one in the UI-Thread). To prepare a Looper for the current thread : call Looper.prepare()