HANDLER, LOOPER, MESSSAGEQUEUE, are very important concept and component in android system, it is USED by all kind of import system service/component, mastering such component is required
Looper: the postman receive/dispatch 'mails'
Looper is the fundemental component which makes any of the Android Application's main thread running. actually when ActivityThread starts running, it makes itself a loop thread.
main(){
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
...
Looper.loop();
}
ActivityThread's main method will get called in AMS, where Process.start() need to create a new Activity thread, and this ActivityThread object is singleton per thread.
A Thread can only become a Looper Thread by Looper.prepare(), except main thread.
Looper: how to create it ?
Looper has no public constructor for you to create a Looper instance. instead, you can only create a looper through:
public static void prepare(){};
public static void prepare(boolean quitAllowed){
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
Looper uses ThreadLocal technics to make sure there is only one instance of Looper per thread, and use lock on Looper.class to make sure access to the instance is sync'ed
Looper: the constructor
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
The MessageQueue Looper created will be the sink for reeiving message from system and from app it self. later, when current thread becomes a looper thread, by calling Looper.loop(), this thread will constantly trying to pull message from the MessageQueue, if there is no message, it is blocked and make into sleep mode(deep down, the messageQueue is trying to read a linux file, this read will block if no more to read).
Looper: loop()
for(;;){
Message msg = MyLooper().mQueue.next();
msg.target.dispatchMessage(msg);
}
That's it !! it is a dead for loop.
Handler : Sending/Handling Messages.
Handler class name is a bit misleading, it not only handles incoming messages, but also does sending messages(or runnables), because sending message/runnable is so generic that you don't need to worry about it, internals of Handler obeject helps you to do such job. all you need to do is implement hanleMessage(Message msg)
Handler : how message is dispatched ?
There are three layers of message handling.
- Message itself, if the message.callback is set, callback.run() get called, this callabck is basically a Runnable, when you post a runnable into the handler's message queue, your runnable is set into a message's callback field.
- Handler.callback, when Handler object is created, there is a choice to set its callback object, if set, this callback will get call.
- if message or handler has no callbacks, handleMessage from your implementation get called.
these 3 methods get called exclusively, i.e. only one methods get called.
Handler: how message is fleshed ?
you noticed that when Looper.loop() retrieve a message from MessageQueue, it calls msg.target.dispatchMessage(msg), what exactly is this target field in a message. a normal use case of Handler will be :
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg){
swtich(msg.what){
...
}
}
}
Message msg = Message.obtain(WHAT);
handler.sendMessage(msg);
handler.post(new Runnable(){
void run(){}
});
There are two ways a Handler object can send a message, or post a runnable. The runnable posted will later on simply set into Message'callback. let first look into sendMessageXXX().
Handler: how to IPC
Handler itself has nothing to do with Handler, so to use handler and its benefits of internal looper and message queue, Handler has a internal binder structure to enable IPC of Handler : Messengers:
If a thread calls
new Handler()
, but it is not a looper thread, this constructor will throw expcetion complain not running on a looper thread.
Message : in detail.
Messenger also use this.