Understand the handler mechanism and handler Mechanism
I,LogoffClass
First of all, you know that a class, The logoff class, as its name implies, is the meaning of the loop operator, so the existence of the logoff class is to make an ordinary thread become a thread that will be executed cyclically, we can understand it as a long-lived medicine.
The general Thread class can be cyclically executed by executing the lorule. prepare () method.
The prepare () method is a static method of The logoff class, as follows:
public class Looper { private static final String TAG = "Looper"; // sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); final MessageQueue mQueue; final Thread mThread; volatile boolean mRun; private Printer mLogging = null; private static Looper mMainLooper = null; // guarded by Looper.class /** 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()}. */ public static void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); }
SThreadLocal is a copy of the independent variables of the thread. It is used to save the logoff object of the thread.
Here, we first know a rule: Everyone can only take one inactive drug. in other words, each thread can have only one associated logoff object.
The get () method is used to determine whether there are any. If there is no, a new one is created. If yes, an exception is thrown. Why is an exception thrown? Because prepare is used for the first time by a thread, it can only be used once. Therefore, there should be no logoff object before using it. The proof is repeated.
Call the set Method of ThreadLocal to associate the logoff object with the current thread. (If you do not understand what ThreadLocal is, you can understand it as a map, map. put (this. thread, new Looper (), the key is the current thread, and the value is the Looper, so associated ).
Note that the logoff class adopts the default constructor method. When a new logoff object is created, a message queue is created.
MessageQueue is called mQueue.
2. Call the loop () method to start the message loop:
The source code of the Loop () method is as follows:
public static void loop() { Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } MessageQueue queue = me.mQueue; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); while (true) { Message msg = queue.next(); // might block if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } long wallStart = 0; long threadStart = 0; // This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); wallStart = SystemClock.currentTimeMicro(); threadStart = SystemClock.currentThreadTimeMicro(); } msg.target.dispatchMessage(msg); if (logging != null) { long wallTime = SystemClock.currentTimeMicro() - wallStart; long threadTime = SystemClock.currentThreadTimeMicro() - threadStart; logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); if (logging instanceof Profiler) { ((Profiler) logging).profile(msg, wallStart, wallTime, threadStart, threadTime); } } // 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.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycle(); } } }
MessageQueue queue = me. mQueue;
These lines of code first obtain the message queue of the current thread, and then there are two lines of code to ensure that the current thread is in the current process. Ignore it. Then, while (true) enters the endless loop.
Message msg = queue. next (); // might block
The next () method of the message queue is used to obtain the message to be processed. Note the comment below. When there is no message to be processed by the current thread () method.
The next () method is used to determine whether there is a message or sleep. You can see the source code.
Okay. Now that the message queue is available, how can thread A send A message to another thread in the message queue of thread B? How does thread B handle this message after receiving it? At this time, the android designer provides a handler class for sending and processing messages.
II,HandlerClass
final MessageQueue mQueue; final Looper mLooper; final Callback mCallback; IMessenger mMessenger;
The Handler class contains the preceding four member variables. Among them, we need to know the message queue variable mQueue and the loop object mloader
The handler class contains many message sending methods.
// 1st Methods public final boolean sendMessage (Message msg) {return sendMessageDelayed (msg, 0);} // 2nd Methods public final boolean sendEmptyMessage (int what) {return sendEmptyMessageDelayed (what, 0);} // 3rd public final boolean sendEmptyMessageDelayed (int what, long delayMillis) {Message msg = Message. obtain (); msg. what = what; return sendMessageDelayed (msg, delayMillis );}
There are also two methods to process messages.
/** * Subclasses must implement this to receive messages. */ public void handleMessage(Message msg) { } /** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
HandleMessage is used to subclass objects to override this method to receive and process messages.
DispatchMessage is used to process system messages.