Pre-order: Each app corresponds to a process, which has a activitythread thread called the main thread (i.e. the main thread of the UI), in addition to other threads, this re-argument.
Android's message system analysis.
- Each thread corresponds to only one looper
- Each looper corresponds to only one MessageQueue
- n a message in each MessageQueue
- Specify a maximum of one handler per message to handle events
- A thread can correspond to multiple handler
The Looper is responsible for extracting messages (message/runnable) from the message queue (MessageQueue) and handing them over to handler.
Message:
Public final class Message implements Parcelable {
public int what;//Each message can specify a handler, because there can be more than one handler, with what to identify the specific handler public int arg1; public int arg2; public Object obj; Public Messenger ReplyTo; /*package*/static final int flag_in_use = 1 << 0; /*package*/static final int flag_asynchronous = 1 << 1; /*package*/static final int flags_to_clear_on_copy_from = Flag_in_use; /*package*/int flags; /*package*/long when; /*package*/Bundle data; /*package*/Handler target;//Specifies which Handler to handle this message/*package*/Runnable callback ; /*package*/message next;//messages chain private static final Object Spoolsync = new Object (); private static message spool;//header of the message list, note is static private static int spoolsize = 0; private static final int max_pool_size = 50;
......
}
MessageQueue is actually an operational encapsulation of the message, and the message queue is a spool-led list of messages:
Public class MessageQueue {//True if the message queue can be quit. Private Final Boolean mquitallowed; @SuppressWarnings ("unused") private int mptr; Used by native code message mmessages;//message ... private final arraylist<idlehandler> midlehandlers = new Arra Ylist<idlehandler> (); Private idlehandler[] mpendingidlehandlers; Private Boolean mquiting; Indicates whether next () is blocked waiting in pollonce () with a Non-zero timeout. Private Boolean mblocked; The next barrier token. Barriers is indicated by messages with a null target whose arg1 field carries the token. private int mnextbarriertoken;
//Call native function to do real processing private native void Nativeinit (); Private native void Nativedestroy (); Private native void nativepollonce (int ptr, int timeoutmillis); Private native void Nativewake (int ptr);
......
}
Looper:
public class Looper { private static final String TAG = "Looper"; Static final threadlocal<looper> sthreadlocal = new threadlocal<looper> ();//thread-related template class private static Looper Smainlooper; Static type, only one final MessageQueue Mqueue;//looper holds the MessageQueue final Thread mthread; Volatile Boolean mrun; Private Printer mlogging;
......
}
Handler:
The public class handler{//is really the class that handles the message: including handling message and pressing the message into the MessageQueue queue final MessageQueue mqueue; Final Looper Mlooper; Final Callback Mcallback; IMessenger Mmessenger, ...}
Loop () Loops for looper:
public static void Loop () {final Looper me = Mylooper (); if (me = = null) {throw new RuntimeException ("No Looper; Looper.prepare () wasn ' t called on this thread. "); Final MessageQueue queue = Me.mqueue; Binder.clearcallingidentity (); Final Long ident = Binder.clearcallingidentity (); for (;;) {//message loop msg = Queue.next ();//might block//get a message if (msg = = NULL) {///message body is empty indicates exit No message indicates that the message queue is quitting. Return }//This must is in a local variable, in case a UI event sets the logger Printer logging = Me.mlogg ing if (logging! = null) {logging.println (">>>>> dispatching to" + Msg.target + "" + Msg.callback + ":" + msg.what); } msg.target.dispatchMessage (msg);//invokes the message specified by the recipient handler to handle it if (logging! = null){logging.println ("<<<<< finished to" + Msg.target + "" + msg.callback); }//Make sure that during the course of dispatching the//identity of the thread wasn ' t corrupted. Final Long newident = Binder.clearcallingidentity (); if (ident! = newident) {LOG.WTF (TAG, "Thread identity changed from 0x" + Long.tohex String (ident) + "to 0x" + long.tohexstring (newident) + "when dispatching to" + Msg.target.getClass (). GetName () + "" + Msg.callback + "what=" + msg.what); } msg.recycle ();//Discard Message, recycle}}
The handler takes a message each time it is fetched from spool (the static message type in message), which invokes the static method:
public static Message obtain (Handler H, int. what, Object obj) { Message M = obtain (); M.target = h; M.what = what; M.obj = obj; return m; }
Handler press messages into Message Queuing:
public boolean sendmessageattime (Message msg, long Uptimemillis) { Boolean sent = false; MessageQueue queue = Mqueue; if (queue! = null) { msg.target = this; Sent = Queue.enqueuemessage (msg, uptimemillis);//Call MessageQueue method to perform a push-in operation } else { runtimeexception E = new RuntimeException (this + "sendmessageattime () called with no Mqueue"); LOG.W ("Looper", E.getmessage (), E); } return sent; }
Summary: Handler the message is taken directly (from the spool), the message is pressed into the MessageQueue is called MessageQueue method.
----------------------------------------------Split Line------------------------------------------------------------------------ ----
The following is an analysis of when these objects were created.
When was the Looper created?
Each thread has only one Looper object.
1. Normal threads (not the main thread)
A typical self-created thread uses looper such as:
Class Looperthread extends thread{public Handler Mhandler; public void Run () { looper.prepare (); Mhandler= New Handler () {public void Handlemessage (Message msg) { //processing Messages } }; Looper.loop ();//Enter message loop }}
When was the Looper created? See Looper.prepare () method: After executing this method, we get a unique looper of this thread.
Static final threadlocal<looper> sthreadlocal = new threadlocal<looper> ();//This is a template class that is first closed to the thread
private static void Prepare (Boolean quitallowed) { if (sthreadlocal.get () = null) {//throws an exception if the caller already has looper on the host thread throw new RuntimeException ("Only one Looper could be created per thread"); } Sthreadlocal.set (New Looper (quitallowed)); thread-local storage in//java, that is, different lines }//to get their own different sthreadlocal object references by Looper
Private Looper (Boolean quitallowed) { mqueue = new MessageQueue (quitallowed);//create Looper to process the message queue Mrun = true; Mthread = Thread.CurrentThread ();//Get current thread }
So how does handler relate to Looper? See how the handler is constructed:
Public Handler () { if (find_potential_leaks) { final class<? extends handler> Klass = GetClass (); if (Klass.isanonymousclass () | | klass.ismemberclass () | | klass.islocalclass ()) && (Klass.getmodifiers () & modifier.static) = = 0) { log.w (TAG, "the following Handler class should be STATIC or leaks might occur:" + Klass.getcanonicalname ()); } } Mlooper = Looper.mylooper ();//through thread-local storage, get the Looper if (mlooper = = null) of this thread { throw new RuntimeException ( " Can ' t create handler inside thread that have not called looper.prepare () "); } Mqueue = Mlooper.mqueue; Mcallback = null; }
public static Looper Mylooper () {//Get Looper return Sthreadlocal.get () associated with this thread; }
Summary: Each thread creates a Looper through sthreadlocal<looper> (which in turn creates a MessageQueue), and then creates a handler (via Sthreadlocal). Thus, handler and Looper are "bound" together to form a complete message circulatory system.
2. Main thread Activitythread
When did the main thread create the Looper? In the main method of Activitythread.java, there are:
public static void Main (string[] args) { samplingprofilerintegration.start (); Closeguard.setenabled (false); Process.setargv0 ("<pre-initialized>"); Looper.preparemainlooper ();//is also Sthreadlocal.set (new Looper (quitallowed)) to create a thread that belongs to the Looper, and through Sthreadlocal.get () assigning Looper to Smainlooper (private static Looper Smainlooper), the Smainlooper function is that other threads can get Looper to the main thread (because Smainlooper is static , which is assigned in the main thread). if (Smainthreadhandler = = null) { Smainthreadhandler = new Handler (); } Activitythread thread = new Activitythread (); Thread.attach (false); Asynctask.init (); if (false) { looper.mylooper (). setmessagelogging (New Logprinter (Log.debug, "Activitythread")); } Looper.loop (); throw new RuntimeException ("Main thread loop unexpectedly exited"); }
Looper.loop () is a static method that, as a message loop processor, constantly takes messages and distributes messages.
Message processing for Android analytics