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.
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 :
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
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
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)
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()