Although the preface has been doing application layer development, but our group is the core system BSP, it is necessary to understand the underlying understanding of Android's operating mechanism. As far as applications are concerned, Java applications on Android are the same on other systems, and they work by message-driven, and they work roughly as follows: 1. There is a message queue where messages can be posted to this message queue. 2. There is a message loop that constantly pulls messages out of the message queue and then processes them. In order to better understand the Android message processing mechanism, these days of free time, I combined with "in-depth understanding of the Android system" looked at handler, Looper, message The source code of these categories, here to share the learning experience.
Looper class analysis Looper literally means "looping," which is designed to turn a normal thread thread into a looper thread. The so-called Looper thread is the thread that loops the work, in the program development (especially GUI development), we often use to a loop executes the thread, has the new task to execute immediately, does not have the new task to circulate waits. Creating the Looper thread with Looper is simple and the sample code is as follows:
Package Com.example.testlibrary;import Android.os.handler;import Android.os.looper;public class LooperTheread Extends Thread{public Handler Mhhandler; @Overridepublic void Run () {//1. Call Looperlooper.prepare ();//... Other processing, such as instantiation of handler//2. Enter message loop Looper.loop ();}}
With the 1, 22-Step core code, your thread is upgraded to a looper thread. Below, we analyze each of the two key calls 1, 2.
Looper.prepare () in the thread that calls prepare, a Looper object is set, and the Looper object is stored in the TLV of the calling thread. A message queue is encapsulated inside the Looper object.
Let's look at the source code of the Looper class. The first calling function is the prepare function of looper, and its source code is as follows:
The Looper object in each thread is actually a ThreadLocal, that is, thread local storage (TLS) object static final threadlocal<looper> sthreadlocal = new Threadlocal<looper> (); public static void Prepare () { prepare (true); } 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)); }
According to the above source, prepare will set a Looper object in the local variable of the calling thread, and a thread can have only one Looper object. This calling thread is the Looperthread run thread. Take a look at the construction source of the Looper object:
Private Looper (Boolean quitallowed) { mqueue = new MessageQueue (quitallowed); Mthread = Thread.CurrentThread (); }
Through the source code, we can easily understand how Looper works, its core is to define the Looper object as threadlocal. If you do not understand threadlocal, you can refer to my article: correct understanding of threadlocal
Looper Loop calls the Loop method, the Looper thread begins to actually work, and it constantly takes out the enemy information (also called the Task) from its own MessageQueue,:
The implementation of the source code is as follows (I've done some trimming here to get rid of the codes that don't affect the main line):
/** * Run The message queue in this thread. Be sure to call * {@link #quit ()} to end of the loop. */public static void loop () {final Looper me = Mylooper (); if (me = = null) {throw new RuntimeException ("No Looper; Looper.prepare () wasn ' t called on this thread. "); Take out this Looper message queue final MessageQueue queue = Me.mqueue; for (;;) {Message msg = Queue.next ();//might block if (msg = = NULL) {//No Message Indicat ES the message queue is quitting. Return }//processes the message with a target, which is the handler type Msg.target.dispatchMessage (msg); Msg.recycle (); }}/** * 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 (); }
The above analysis will show that the role of Looper is: 1. Encapsulates a message queue. 2. The prepare function of Looper binds this looper to the thread that invokes prepare (that is, the thread that is finally processed) and is implemented by the threadlocal mechanism. 3. The processing thread calls the loop function to process messages from the message queue. How to add a message to MessageQueue, is implemented by handler, the following to analyze the handler.
Handler analysis what is handler? Handler plays the role of adding messages and processing messages to the MessageQueue (only the messages sent by itself), that is, by MessageQueue it performs a task (SendMessage), and perform the task (handlemessage) while looping to itself, the entire process is asynchronous. The members included in the initial knowledge of Handlerhandler:
Final MessageQueue mqueue;//Handler also has a message queue final Looper mlooper;//also has a Looper final Callback mcallback;// There is a callback class
The use of these several member variables requires analysis of the handler constructor. Handler altogether has four constructors, the difference lies in the initialization of the above member variables, let's take a look at the source code of the four constructors:
Constructor 1 public Handler () {//Gets the calling thread's Looper Mlooper = Looper.mylooper (); if (Mlooper = = null) {throw new RuntimeException ("Can ' t create handler inside thread that Have not called Looper.prepare () "); }//Get looper message Queue mqueue = Mlooper.mqueue; No callback setting mcallback = NULL; }//Constructor 2 public Handler (Callback Callback) {//Get the calling thread's Looper Mlooper = Looper.mylooper (); if (Mlooper = = null) {throw new RuntimeException ("Can ' t create handler inside thread that Have not called Looper.prepare () "); }//Get looper message Queue mqueue = Mlooper.mqueue; Compared with the constructor 1, the callback setting Mcallback = callback; }//Constructor 3 public Handler (Looper Looper) {//Looper is passed in by external, which thread is Looper indeterminate mlooper = Looper; Mqueue = Mlooper.mqueue; Mcallback = null; }//Constructor 4 public Handler (Looper Looper, Callback Callback) {mlooper = Looper; Mqueue = Looper.mqueue; Mcallback = callback; }
From the above constructor, we can find that the MessageQueue in handler will eventually point to the MessageQueue of the associated Looper. Handler true colors from the above analysis, handler in the message queue is actually a looper message queue, we can add handler for the previous Looperthread class, the code is as follows:
public class Looperthread extends Thread{public Handler mhhandler; @Overridepublic void Run () {//1. Calling Looperlooper.prepar E ();//... Other processing, such as instantiation of handlerhandler handler = new handler ();//2. Enter message loop Looper.loop ();}}
Join handler as follows: Ask a question, assuming that there is no handler, how can we insert a message into the MessageQueue of Looper? Here I say an original idea: 1. Calls Looper's Myqueue, which returns the Message Queue object MessageQueue. 2. Construct a message to populate its members, especially the target object. 3. Call MessageQueue's enqueuemessage and insert the message into the message queue. Although the above method works, but very primitive, with the handler, it is like an auxiliary class that provides a series of API calls that help us simplify our programming efforts. Common APIs are as follows: 1. Post (Runnable) 2. Postattime (Runnable, Long) 3. Postdelayed (Runnable, Long) 4. Sendemptymessage (int) 5. SendMessage (Message) 6. Sendmessageattime (Message, long) 7. sendmessagedelayed (message, long) light look at the above API, you would think that handler may send two kinds of information, one is Runnable object, one is a message object, this is subjective understanding, but from the source we can see, The Runnable object sent by post is finally encapsulated as a message object with the following source code:
Public Final Boolean post (Runnable R) { return sendmessagedelayed (Getpostmessage (R), 0); } private static Message Getpostmessage (Runnable r) { Message M = Message.obtain ();//Get empty message M.callback = r;// Set Runnable to callback return m of message; } Public Final Boolean sendmessagedelayed (Message msg, long Delaymillis) { if (Delaymillis < 0) { Delaymillis = 0; } Return Sendmessageattime (MSG, systemclock.uptimemillis () + Delaymillis); }
The final send message will call the Sendmessageattime function, let's look at its source code implementation:
public boolean sendmessageattime (Message msg, long Uptimemillis) { MessageQueue queue = mqueue; if (queue = = null) { runtimeexception e = new RuntimeException (this + "sendmessageattime () called with no Mqueue "); LOG.W ("Looper", E.getmessage (), e); return false; } return Enqueuemessage (Queue, MSG, uptimemillis); } Private Boolean enqueuemessage (MessageQueue queue, message msg, long Uptimemillis) { msg.target = this;//The t of the message Arget is set to itself and then added to the message Queue if (masynchronous) { msg.setasynchronous (true); } Return Queue.enqueuemessage (msg, uptimemillis); }
Handler handles the message and then looks at how handler handles the message. The processing of the message is done through the core method DispatchMessage (Message msg) and the Hook method handlemessage (Message msg), the source code is as follows:
/** * Handle system messages here. */public void DispatchMessage (Message msg) {if (msg.callback! = null) {handlecallback (msg); } else {if (mcallback! = null) {if (Mcallback.handlemessage (msg)) {retur N }} handlemessage (msg); }} private static void Handlecallback (Message message) {Message.callback.run (); }/** * Subclasses must implement this to receive messages. */public void Handlemessage (Message msg) {}
DispatchMessage defines a set of priority mechanisms for message processing, which are: 1. If the message comes with callback processing, it is handed to callback for processing. 2. If the handler has a global mcallback set, it is given to mcallback processing. 3. If none of the above is true, the message is passed to the Handlermessage (message msg) implemented by the handler subclass for processing. Of course, this needs to derive from handler and override the Handlermessage function. In the case of adoption, we generally adopt a third method, that is, to complete the processing work by overloading the handlermessage in subclasses. The usefulness of handler after reading the handler message and processing the message, let's learn the true beauty of handler, known as the Master of asynchronous processing. Hanlder has two important features: 1. Handler can send messages on any thread that is added to the Looper message queue in handler.
2. Handler is the processing of messages in its associated looper thread.
This solves an issue where Android classics cannot update the UI in a non-main thread. The main thread of Android is also a looper, and the handler we create in it will default to the message queue Looper the main thread. Therefore, we can create the handler object on the main thread, after the time consuming child thread obtains the UI information, through the main thread's handler object reference to the main thread, informs the modification UI, of course the message can also contain the concrete UI data.
Message in the entire messaging mechanism, the message is also called a task, encapsulating the messages carried by the task and the handler that handle the task. The source of the message is relatively simple, here are a few notes: 1. Although the message has a public default constructor, you should use Message.obtain () to obtain an empty message object from the message pool to conserve resources, as follows:
/** * Return A new Message instance from the global pool. allows us to * Avoid allocating new objects in many cases. */public static Message obtain () { synchronized (spoolsync) { if (sPool! = null) { Message m = spool;
spool = M.next; M.next = null; spoolsize--; return m; } } return new Message (); /** Constructor (But the preferred-to-get a Message is to call {@link #obtain () Message.obtain ()}). * /Public Message () { }
2. If your message only needs to carry simple int information, you should prioritize using MESSAGE.ARG1 and message.arg2 to pass information, which saves memory than using Bundler.
/** * arg1 and Arg2 is lower-cost alternatives to using * {@link #setData (Bundle) setData ()} If you have need to Store a * few integer values. */public int arg1; /** * arg1 and Arg2 is lower-cost alternatives to using * {@link #setData (Bundle) setData ()} If you have need to Store a * few integer values. */public int arg2; /** * Sets a Bundle of arbitrary data values. Use Arg1 and arg1 the members * as a lower the cost of the to send a few simple integer values, if you can. * @see #getData () * @see #peekData () */public void SetData (Bundle data) { this.data = data; }
3. Use Message.what to identify information so that the message can be processed in different ways.
The sample code writes a sub-thread that uses the main thread handler to update the UI's sample code, as follows:
public class Mainactivity extends Activity {TextView mtextview; MyHandler Mhandler = new MyHandler (), @Overrideprotected void OnCreate (Bundle savedinstancestate) {super.oncreate ( Savedinstancestate); Setcontentview (r.layout.activity_main); Mtextview = (TextView) Findviewbyid (R.ID.TEST1); new Thread (New Updatetitletask (Mhandler)). Start (); Private class MyHandler extends Handler {@Overridepublic void Handlemessage (Message msg) {Bundle bundle = Msg.getdata (); MT Extview.settext (bundle.getstring ("title", ""));}}}
public class Updatetitletask implements Runnable{private Handler handler;public updatetitletask (Handler Handler) { This.handler = handler;} Private Message preparemsg () {Message msg = Message.obtain (); Bundle bundle = new bundle (); Bundle.putstring ("title", "from Update Task");; Msg.setdata (bundle); return msg;} @Overridepublic void Run () {try {thread.sleep (2000); Message msg = preparemsg (); Handler.sendmessage (msg);} catch (Interruptedexception e) {}}}
Ref. 1. "In-depth understanding of Android Volume One" 2. Http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html