Android asynchronous message mechanism architecture:
The Android asynchronous message processing architecture is actually not that complicated. Simply put, the looper
object owns messagequeue
and is responsible messagequeue
for fetching messages from it handler
for processing. It handler
is also responsible for sending message
to , and adding to the tail looper
by looper
putting . Just a circle. An illustration is given below:message
messagequeue
So it's clearly linked with the come handler
. looper
It should be noted that multiple message
can point to the same one handler
, and multiple handler
can also point to the same one looper
. Another important point is that there are no ordinary threads looper
. If you need an looper
object, you must call the Looper.prepare()
method first, and a thread can only have one looper
. After the call is completed, this thread becomes the so-called LooperThread
. If an object LooperThread
is created in the current Handler
, then this Handler
will be automatically associated with the object of the current thread looper
, that is, the owned looper
reference.
Looper
Looper
Is a management messagequeue
class. Below is the source code for this class.
public class Looper { ...... private static final ThreadLocal sThreadLocal = new ThreadLocal(); final MessageQueue mQueue;//Owned message queue ...... /** * Initialize the current thread as a looper. * This gives you a chance to create handlers that then reference * this looper, before actually starting the loop. Be sure to call * {@link #loop()} after calling this method, and end it by calling * {@link #quit()}. */ //Create a new looper object and set it to the current thread public static final void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); } ····· /** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */ //Get the looper object of the current thread public static final Looper myLooper() { return (Looper) sThreadLocal.get(); } private Looper() { mQueue = new MessageQueue(); mRun = true; mThread = Thread.currentThread(); } ...... }
After the call is complete Looper.prepare()
, only those created by the Handler
current thread can own the current thread looper
. Then call loop()
to start the loop, process message
. The following is part of the source code of the loop method under the Looper class:
public static void loop() { final Looper me = myLooper();//Get the looper object if (me == null) { //If it is empty, it means that the current thread is not LooperThread, and an exception is thrown throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; get message queue ..... for (; ; ) { // The infinite loop keeps taking out the message Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. //No message indicates that the message queue has exited return; } // This must be in a local variable, in case a UI event sets the logger //Print the log, indicating that the message is processed. msg.target is the Handler object Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } // point! ! ! Start processing the message, msg.target is the Handler object msg.target.dispatchMessage(msg);//dispatchMessage: send message //Print log, process message ends if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } ..... } }
It is a large loop, constantly taking out messages from the message queue. Then call a very critical method msg.target.dispatchMessage(msg)
to start processing the message. msg.target
is message
corresponding handler
. looper
Object management MessageQueue
, take it out and message
assign it to the corresponding one handler
for processing.
Message
Message
It is some events that need to be processed, such as accessing the network, downloading pictures, updating the UI interface, etc. Message
has several important properties.
public int what identifier, used to identifymessage
public int arg1, arg2 can be used to pass some lightweight data such as int
Message
The Object class field that comes with public Object obj is used to pass objects
Handler target refers to the message
correspondingHandler
If you carry data of price comparison complexity, it is recommended to use Bundle
encapsulation. It is worth noting that although Message
the construction method is public, it is not recommended to use. The best way is to use Message.obtain()
or Handler.obtainMessage()
make better use of the objects in the loop pool. Generally, there is no need to manually set target
it, the calling Handler.obtainMessage()
method will be automatically set Message
to the target
current one Handler
. After getting Message
it, you can call sendToTarget()
it, send a message to it Handler
, and Handler
put the message messagequeue
at the end. The source code for this method is as follows:
/** * Sends this Message to the Handler specified by {@link #getTarget}. * Throws a null pointer exception if this field has not been set. */ public void sendToTarget() { target.sendMessage(this);//The target here is the Handler corresponding to the message. }
Handler
Its constructor is as follows:
/** * Default constructor associates this handler with the {@link Looper} for the * current thread. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. */ public Handler() { this(null, false); } /** * Constructor associates this handler with the {@link Looper} for the * current thread and takes a callback interface in which you can handle * messages. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. * * @param callback The callback interface in which to handle messages, or null. */ public Handler(Callback callback) { this(callback, false); } /** * Use the provided {@link Looper} instead of the default one. * * @param looper The looper, must not be null. */ public Handler(Looper looper) { this(looper, null, false); } /** * Use the provided {@link Looper} instead of the default one and take a callback * interface in which to handle messages. * * @param looper The looper, must not be null. * @param callback The callback interface in which to handle messages, or null. */ public Handler(Looper looper, Callback callback) { this(looper, callback, false); } /** * Use the {@link Looper} for the current thread * and set whether the handler should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */ public Handler(boolean async) { this(null, async); } /** * Use the {@link Looper} for the current thread with the specified callback interface * and set whether the handler should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param callback The callback interface in which to handle messages, or null. * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */ public Handler(Callback callback, boolean async) { 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: " + class.getCanonicalName ()); } } mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; } /** * Use the provided {@link Looper} instead of the default one and take a callback * interface in which to handle messages. Also set whether the handler * should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param looper The looper, must not be null. * @param callback The callback interface in which to handle messages, or null. * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */ public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; // It can be seen that it has thelooper
object, andlooper
themessagequeue
mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }
To Handler
handle events through, it can be rewritten handleMessage(Message msg)
, or it can be handled directly through post(Runnable r)
. Both methods will be called in the looper loop.
The source code of the method of processing information in the loop loop msg.target.dispatchMessage(msg)
:
public void dispatchMessage(Message msg) {
//Notice! Here, first determine whether the callback of the message is empty, otherwise, directly process the callback function of the message
if (msg.callback!= null) { // The callback here is the Runnable above
handleCallback(msg);
} else {
if (mCallback != null) {
//It is here that we usually override handleMessage
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
First, judge whether the handler's post method is used. If so, execute the code of the run() method in r. Otherwise, judge whether the handler's constructor has initialized CallBack. If so, it will execute the handleMessage(msg) method in this interface. ; If false is put back, handleMessage(msg) will be called at the end (the method overridden when the handler is established, if it is not overridden, nothing will be executed). The following is the source code of the handler's post method:
/**
* Causes the Runnable r to be added to the message queue.
* The runnable will be run on the thread to which this handler is
* attached.
*
* @param r The Runnable that will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);//Send message
}
The source code of the getPostMessage(r) method in the above source code:
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r; //It is the above msg.callback, if the handler's post method is called, it will not be empty.
return m;
}
The above if (msg.callback!= null) { // The callback here is the handleCallback(msg) source code of the above Runnable handleCallback(msg); }: (that is, the code in the run method)
private static void handleCallback(Message message) {
message.callback.run();
}
The source code of handleMessage(msg) in if (mCallback.handleMessage(msg)) { return; } is as follows:
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
public interface Callback {
public boolean handleMessage(Message msg);
}
msg.target.dispatchMessage(msg)
So now you know the code in the method of processing information in the loop loop .