first, take a look at the use of the process
1. Using handler instances in child threads
/*********** Child Threads Use Handler instance *********/ private class Looperthread extends thread {public Handler Handler; @Override public Void Run () { looper.prepare (); Handler = new Handler () { @Override public void Handlemessage (Message msg) { } }; Looper.loop (); } }
2. Handler,looper used in the main thread (UI thread), etc.In fact now the Android/app/acitvitythread.java file, as follows:
public static void Main (string[] args) {//The preceding series of configurations do not care Samplingprofilerintegration.start () for the time being; Closeguard.setenabled (FALSE); Environment.initforcurrentuser (); Eventlogger.setreporter (New Eventloggingreporter ()); Security.addprovider (New Androidkeystoreprovider ()); Final File Configdir = Environment.getuserconfigdirectory (Userhandle.myuserid ()); Trustedcertificatestore.setdefaultuserdirectory (Configdir); Process.setargv0 ("<pre-initialized>"); /************ from here, use looper*******************/looper.preparemainlooper ();//contrast: Use Looper.prepare () in child threads; Activitythread thread = new Activitythread (); Thread.attach (FALSE); if (Smainthreadhandler = = null) {Smainthreadhandler = Thread.gethandler ();//contrast: Create a new Handler ()} from a child thread if (false) {Looper.mylooper (). setmessagelogging (New Logprinter (Log.debug, "activityt Hread ")); } Looper. loop ();//contrast: Here Both the same throw new RuntimeException ("Main thread loop unexpectedly exited"); }
Second, view the source code:(i) Prepare ()1, look at the source of Looper.prepare () :
/** initializes the current thread to a looper. So you can create a handlers before the start loop, and then reference the Looper; * Make sure to call the #loop () method after calling this method; end this method use #quit (); */public static void Prepare () { prepare (true) ; Contrast: Below you will see that preparemainlooper in the main thread will use prepare (false) } private static void Prepare (Boolean quitallowed) { if (sthreadlocal.get () = null) { throw new RuntimeException ("Only one Looper could be created per thread"); } Sthreadlocal.set (new Looper (quitallowed)); }
attached i) here leads to asthreadlocal, first look at its definition:
Sthreadlocal.get () would return null unless you ' ve called prepare (). Static final threadlocal<looper> sthreadlocal = new threadlocal<looper> ();
The Threadlocal class is a special global variable that is only represented by its own thread (the class name also manifests the feature), so the looper of each thread is independent;The Threadlocal class Java itself has been implemented, and Android has optimized it, and the main idea remains:how does threadlocal maintain a copy of a variable for each thread? In fact, the idea of implementation is simple, there is a map in the Threadlocal class that stores a copy of each thread's variable,thekey of the element in map is the thread object, and the value corresponds to the variable copy of the thread .
the previous source refers to the get (), set (0 method is to get and set the thread local variable value corresponding to the current thread.
2, see
/** * Initialize The current thread as a looper, marking it as an * application ' s main looper. The main looper for your application * are created by the Android environment, so we should never need * to call T His function yourself. See also: {@link #prepare ()} */public static void Preparemainlooper () { prepare (false); Synchronized (looper.class) { if (smainlooper! = null) { thrownew illegalstateexception ("The main Looper has AL Ready been prepared. "); Smainlooper = Mylooper (); } } /** * Return The Looper object associated with the current thread. Returns * NULL if the calling thread is not associated with a Looper. * /public static Looper Mylooper () { return sthreadlocal.get (); }
attached II):Smainlooperdefinition of:
private static Looper Smainlooper;
roughly the same as before, just defines a Smainlooper , get sthreadlocal get a looper, let Smainlooper point to it;
Two Handler
1, handler part of the source code:
Handler many constructors:
Public Handler () {This (null, false); } public Handler (Callback Callback) {This (Callback, false); } public Handler (Looper Looper) {This (Looper, NULL, FALSE); } public Handler (Looper Looper, Callback Callback) {This (Looper, Callback, false); } public Handler (Boolean async) {This (null, async); } public Handler (Looper Looper, Callback Callback, Boolean async) {mlooper = Looper; Mqueue = Looper.mqueue; Mcallback = callback; masynchronous = async; }/**************** focuses on this constructor *********************/public Handler (Callback Callback, Boolean async) {if (find_ Potential_leaks) {final class<? extends handler> Klass = GetClass (); if (Klass.isanonymousclass () | | klass.ismemberclass () | | klass.islocalclass ()) && (Klass.getmo Difiers () & modifier.static) = = 0) {LOG.W (TAG, "the following Handler class should Be static or leaks might occur: "+ klass.getcanonicalname ()); }}/*************** before ignoring, starting from here to see ******************/mlooper = Looper.mylooper ();//still acquired through sthreadlocal to the current th Read the Looper instance, which is visible here together if (Mlooper = = null) {throw new RuntimeException ("Can ' t creat e handler inside thread that have not called looper.prepare () "); } mqueue = Mlooper.mqueue; Here MessageQueue is looper and handler communication bridge Mcallback = callback; masynchronous = async; }
attached i)Mqueuedefinition of:FinalMessageQueue Mqueue;
Visible through the Messagequeue,handler and Looper linked together;
(iii) Looper.loop () process of event processing
public static void Loop () {final Looper me = Mylooper ();//still gets the Looper instance of the current thread through sthreadlocal if (me = = null) {throw new RuntimeException ("No Looper; Looper.prepare () wasn ' t called on this thread. "); Final MessageQueue queue = me.mqueue;//Gets the MessageQueue mqueue binder.clearcallingidentity () mentioned above; Final Long ident = Binder.clearcallingidentity (); /**************** loop Processing message *******************/for (;;) {Message msg = Queue.next ();//Remove next message from MessageQueue if (msg = = NULL) {//No mess Age indicates, the message queue is quitting. Indicates that the current MessageQueue is exiting return; }//debug information, skip Printer logging = me.mlogging; if (logging! = null) {logging.println (">>>>> dispatching to" + Msg.target + "" + Msg.callback + ":" + msg.what); }/** StartDispatch message */Msg.target.dispatchMessage (msg); definition in//message handler target, so DispatchMessage Finally call the processing function in handler; /** Debug Information, Skip */if (logging! = null) {logging.println ("<<<<< finished to" + msg.t Arget + "" + msg.callback); } 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.recycleunchecked ();//Recycle Processed messages message}}
The Upper loop () method can simply conclude that looper is used to process the extracted message in MessageQueue, which is shared by MessageQueue handler and Looper, The message taken is referred to handler for processing. Handler is also able to add a message to the MessageQueue by post or send for looper subsequent removal. Sthreadlocal ensures that the looper is thread-private and that all information is sent and processed in this thread.
prepare () is used to create a key-value pair for the thread in sthreadlocal that corresponds to the thread looper, and the gethandler created by new handler or handler is obtained from Sthreadlocal.get (). The created handler and Looper shared Messagequeue;loop begin to cycle through the events in the MessageQueue. It is the entire process.
An analysis of the relationship between Handler,looper,message,messagequeue