MessageQueue code: HTTP://GREPCODE.COM/FILE_/REPOSITORY.GREPCODE.COM/JAVA/EXT/COM.GOOGLE.ANDROID/ANDROID/5.1.1_R1/ Android/os/messagequeue.java/?v=source
Handler code:
http://grepcode.com/file_/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/os/ Handler.java/?v=source
Looper Code:
http://grepcode.com/file_/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/os/ Looper.java/?v=source
The message mechanism of handler mainly involves three aspects:
- Message sender;
- Message Queuing;
- The message processing loop operation.
Message Sent:
Public Final Boolean More ... sendMessage (Message msg) { returnsendmessagedelayed (msg, 0); }
Go down:
Public Final Boolean Long Delaymillis) { if (Delaymillis < 0) { = 0; } return sendmessageattime (msg, systemclock.uptimemillis () + delaymillis); }
Finally come here:
Public BooleanMore ... sendmessageattime (Message msg,LongUptimemillis) {MessageQueue Queue=Mqueue; if(Queue = =NULL) {runtimeexception e=NewRuntimeException ( This+ "Sendmessageattime () called with no Mqueue"); LOG.W ("Looper", E.getmessage (), E); return false; } return enqueuemessage (queue, MSG, uptimemillis); }
Call Enqueuemessage to insert a message in the message queue, and in Enqueuemessage total, the msg.target is set to the current handler object.
Private Boolean Long Uptimemillis) { this; if (masynchronous) { msg.setasynchronous (true); } return queue.enqueuemessage (msg, uptimemillis);}
Insert the message into the message queue as follows. And it can be seen clearly that Message Queuing is a linear linked list structure.
BooleanEnqueuemessage (Message msg,LongWhen ) { if(Msg.target = =NULL) { Throw NewIllegalArgumentException ("Message must has a target.")); } if(Msg.isinuse ()) {Throw NewIllegalStateException (msg + "This message was already in use.")); } synchronized( This) { if(mquitting) {illegalstateexception e=Newillegalstateexception (Msg.target+ "Sending message to a Handler on a dead thread"); LOG.W ("MessageQueue", E.getmessage (), E); Msg.recycle (); return false; } msg.markinuse (); Msg.when=When ; Message P=mmessages; BooleanNeedwake; if(p = =NULL|| When = = 0 | | When <p.when) {//New Head, Wake up the event queue if blocked.Msg.next =p; Mmessages=msg; Needwake=mblocked; } Else { //Inserted within the middle of the queue. Usually we don ' t has to wake//Up the event queue unless there are a barrier at the head of the queue//The message is the earliest asynchronous message in the queue.Needwake = mblocked && P.target = =NULL&&msg.isasynchronous (); Message prev; for (;;) {prev=p; P=P.next; if(p = =NULL|| When <p.when) { Break; } if(Needwake &&p.isasynchronous ()) {Needwake=false; }} Msg.next= P;//Invariant:p = = Prev.nextPrev.next =msg; } //We can assume mptr! = 0 because mquitting is false. if(Needwake) {nativewake (mptr); } } return true;}
Each thread can run only one Looper object, and when the Looper is created, a message queue MessageQueue is created internally, and Looper must first be prepare (). Loop again to MessageQueue the message queue for the traversal loop operation.
Public Static voidLoop () {FinalLooper me =Mylooper (); //If the Looper object is empty, the prompt must be created at the current thread through Looper.prepare () if(Me = =NULL) { Throw NewRuntimeException ("No Looper; Looper.prepare () wasn ' t called on the This thread. "); } //If looper is not NULL, take out Message Queuing FinalMessageQueue queue =Me.mqueue; Binder.clearcallingidentity (); Final LongIdent =binder.clearcallingidentity (); //Traverse Message Queue for (;;) {Message msg= Queue.next ();//might block if(msg = =NULL) { //No message indicates that the message queue is quitting. //No message interrupt operation return; } //----------------The queue is not a null operation----------------//This must is in a local variable with case a UI event sets the loggerPrinter logging =me.mlogging; if(Logging! =NULL) {logging.println (">>>>> dispatching to" + Msg.target + "" +Msg.callback+ ": " +msg.what); } //----------------queue is not NULL, distributing data out----------------msg.target.dispatchMessage (msg); if(Logging! =NULL) {logging.println ("<<<<< finished to" + Msg.target + "" +msg.callback); } //Make sure that during the course of dispatching the//The identity of the thread wasn ' t corrupted. Final LongNewident =binder.clearcallingidentity (); if(Ident! =newident) {LOG.WTF (TAG,"Thread identity changed from 0x" + long.tohexstring (Ident) + "to 0x" + Lon G.tohexstring (newident) + "while dispatching to" + Msg.target.getClass (). GetName () + "" + Msg.callback + "what=" +msg.what); } msg.recycleunchecked (); } }
Loop through and distribute messages out msg.target.dispatchMessage (msg):
/*** Handle system messages here. * First, if the message's callback is not empty, it calls Handlecallback processing. Otherwise, it determines whether the Handler mcallback is empty or not, and calls its Handlemessage method. If it is still empty, call Handler's own handlemessage, which is the method we override when we create the Handler */ Public voidDispatchMessage (Message msg) {if(Msg.callback! =NULL) {handlecallback (msg); } Else { if(Mcallback! =NULL) { if(Mcallback.handlemessage (msg)) {return; } } //Callback Handler Handlemessage (msg) method to receive data handlemessage (msg); }}
Well, write this first, and take the time to see it tomorrow, and try to minimize the mistakes.
Handler message mechanism