Android-handler Source code parsing -handler
Member variables
// Check for potential leaks
private static final boolean FIND_POTENTIAL_LEAKS = false;
/ / Log Tag
private static final String TAG = "Handler";
// Main thread Handler
private static Handler MAIN_THREAD_HANDLER = null;
// Looper of this Handler
@UnsupportedAppUsage
final Looper mLooper;
// This Handler's message queue comes from the Looper object.
final MessageQueue mQueue;
// When this Handler distributes the message, the Callback of the message takes precedence.
@UnsupportedAppUsage
final Callback mCallback;
// Whether to send or POST messages are all asynchronous messages. The default value is false.
final boolean mAsynchronous;
// Cross-process communication, message sender.
@UnsupportedAppUsage
IMessenger mMessenger;
Copy the code
Description:
Handler
Why you need to holdLooper
,MessageQueue
Because theHandler
Send a message, etcOperation needs to knowWhich to sendMessageQueue
And theMessageQueue
Need fromLooper
In order to obtainSent messageAble toPolling distribution 。Looper
For more information, please seeTripartite library -Handler source code parsing -Looper.MessageQueue
For more information, please seeTripartite library -Handler source code parsing -MessageQueue.
Create a Handler
To use a Handler, you first need to create a Handler, so let’s take a look at how it is created.
new Handler()
The default stars
Handler()
@Deprecated
public Handler(a) {
this(null.false);
}
Copy the code
Handler(Callback)
@Deprecated
public Handler(@Nullable Callback callback) {
this(callback, false);
}
Copy the code
Handler(Callback, boolean)
/ * *@hide* /
public Handler(@Nullable Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
// Check for potential leaks
final Class<? extends Handler> klass = getClass();
if((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) = =0) {
// Anonymous class, member class, local class, and not static, warning (the following Handler class should be static, otherwise it might leak).
Log.w(TAG, "The following Handler class should be static or leaks might occur: "+ klass.getCanonicalName()); }}// Get the current thread's Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
Handler cannot be created in a thread that did not call looper.prepare ().
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
// Get the message queue of Looper
mQueue = mLooper.mQueue;
/ / record the CallBack
mCallback = callback;
// Whether the record is asynchronous
mAsynchronous = async;
}
Copy the code
For the above constructor, use the default Looper (Looper for the current thread). If the thread has no looper, an exception is thrown.
Description:
Handler()
,Handler(Callback)
Two constructorsHas been markedfor@Deprecated
(out of date), because inHandler
Tectonic processimplicitSelect aLooper
Could lead toerror, where the operation willAutomatic loss(ifHandler
No need for a new mission andexit),collapse(ifhandler
Sometimes in aNo activationLooper
threadoncreate), orA race condition, includinghandler
The associatedthreadNot what the author expected. Instead, it can be usedjava.util.concurrent.Executor
, or usingLooper.getMainLooper
, {link
android.view.View#getHandler
} orSimilar tools are explicitly specifiedLooper
. If for the sake ofcompatibilityNeed to hidethread local
Behavior, then usenew Handler(Looper.myLooper())
Make it clear to the reader.Handler(Callback, boolean)
Two constructors have been marked as@hide
(Hidden), onlyWithin the systemUse.- useThe defaultthe
Looper
(The current threadtheLooper
), if thisthreadThere is nolooper
,An exception is thrown.- parameter
Callback
And for this reasonHandler
Distribution of the messageWhen,Give priority tomessage-processingCallback
, see below for detailsDistribution of the Message.- parameter
async
And for this reasonHandler
Send a messageWhether,allsendAsynchronous/synchronous(the defaultsynchronous) message, see below for detailsSend the Message.- Asynchronous messagingsaidDon’t needrightA synchronous messageforGlobal orderingtheinterruptorThe event.Asynchronous messagingIs not affected by
MessageQueue.postSyncBarrier(long)
The introduction ofSynchronization barrierThe influence of.MessageQueue
For an introduction to synchronization barriers, seeTripartite library -Handler source code parsing -MessageQueue- Synchronization barrier.
To specify which
Handler(Looper)
public Handler(@NonNull Looper looper) {
this(looper, null.false);
}
Copy the code
Handler(Looper, Callback)
public Handler(@NonNull Looper looper, @Nullable Callback callback) {
this(looper, callback, false);
}
Copy the code
Handler(Looper, Callback, boolean)
/ * *@hide* /
@UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
Copy the code
The above constructor uses the specified Looper instead of the default Looper.
Description:
Handler(Looper)
,Handler(Looper, Callback)
Two constructorsNot markedfor@Deprecated
(obsolete), and useThe specifiedtheLooper
.recommendedUse.Handler(Looper, Callback, boolean)
The constructor has been marked as@hide
(Hidden), onlyWithin the systemUse.
Handler.createAsync()
Handler.createAsync(Looper)
@NonNull
public static Handler createAsync(@NonNull Looper looper) {
if (looper == null) throw new NullPointerException("looper must not be null");
return new Handler(looper, null.true);
}
Copy the code
Handler.createAsync(Looper, Callback)
@NonNull
public static Handler createAsync(@NonNull Looper looper, @NonNull Callback callback) {
if (looper == null) throw new NullPointerException("looper must not be null");
if (callback == null) throw new NullPointerException("callback must not be null");
return new Handler(looper, callback, true);
}
Copy the code
The handler.createAsync () method, for static methods, creates an asynchronous Handler whose published Message is not affected by synchronization barriers such as displaying vsync.
Description:
- Sent to theasynchronous
handler
Messages can be guaranteed to be in order from one another, but not necessarily from anotherHandlers
To sort the messages.
summary
- create–synchronous
Handler
, divided intoIs not specifiedLooper
,The specifiedLooper
One of two wayscreate.
- Is not specified
Looper
, use theThe current threadtheLooper
.Is not recommendedUse.- The specified
Looper
.recommendedWith, the constructor isHandler(Looper)
,Handler(Looper, Callback)
.
- create–asynchronous
Handler
, the use ofHandler.createAsync(Looper)
,Handler.createAsync(Looper, Callback)
methodscreate.
Create a Message
To use a Message, you can create a Message with a Handler, so let’s take a look at how it is created.
obtainMessage()
@NonNull
public final Message obtainMessage(a) {
return Message.obtain(this);
}
@NonNull
public final Message obtainMessage(int what) {
return Message.obtain(this, what);
}
@NonNull
public final Message obtainMessage(int what, @Nullable Object obj) {
return Message.obtain(this, what, obj);
}
@NonNull
public final Message obtainMessage(int what, int arg1, int arg2) {
return Message.obtain(this, what, arg1, arg2);
}
@NonNull
public final Message obtainMessage(int what, int arg1, int arg2, @Nullable Object obj) {
return Message.obtain(this, what, arg1, arg2, obj);
}
Copy the code
The obtainMessage() method above returns a new message from the global message pool. Internally, the Message is created using the message.obtain () method and the target of its Message is the current Handler.
Description:
Message.obtain()
For more information, please seeTripartite library -Handler source code parsing -Message- create Message.
summary
handler.obtainMessage()
Method, usingMessage.obtain()
methodsCreate a messageAnd should beMessage
thetarget
For the currentHandler
.
Send the Message
After Message is created, the Message can be sent. In addition to sending the Message via sendMessage(), the Handler can also perform the specified Callback task via POST (), so let’s take a look at how they are sent.
send-Message
sendMessage()
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
Copy the code
sendEmptyMessage()
public final boolean sendEmptyMessage(int what) {
return sendEmptyMessageDelayed(what, 0);
}
Copy the code
sendEmptyMessageDelayed()
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
Copy the code
sendEmptyMessageAtTime()
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
Copy the code
sendMessageDelayed()
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
Copy the code
sendMessageAtTime()
public boolean sendMessageAtTime(@NonNull 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);
}
Copy the code
sendMessageAtFrontOfQueue()
public final boolean sendMessageAtFrontOfQueue(@NonNull Message msg) {
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, 0);
}
Copy the code
The above methods include sending immediate messages, sending delayed messages, sending time-specific messages, and placing messages at the front of the message queue.
Description:
sendMessage()
,sendEmptyMessage()
forSend instant messageThe message,sendMessageDelayed()
,sendEmptyMessageDelayed()
forSending delayed messagesThe message,sendMessageAtTime()
forSends a specified time message.sendMessageAtFrontOfQueue()
forQueue messages to the front of the message queue.sendMessageAtFrontOfQueue()
forQueue messages to the front of the message queueSo that in the messageloop
theThe next timeIterative processing. This methodUsed only for very special purposesIt’s easy to makeMessage queue starvation,Cause sorting problemsorTo produce otherunexpectedSide effects.- Send instant message,Sending delayed messages,Send at specified time,Queue messages to the front of the message queueAll they end up calling is
enqueueMessage()
Methods.
Let’s look at the enqueueMessage() method next.
enqueueMessage()
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
// Specify a Message Handler for this Handler
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
// If this Handler is asynchronous, all messages sent are asynchronous.
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// use MessageQueue to add messages to the MessageQueue
return queue.enqueueMessage(msg, uptimeMillis);
}
Copy the code
Method enqueueMessage() to add a Message to a MessageQueue.
Description:
- The specifiedthis
Message
thetarget
forthisHandler
To makethisMessage
andthisHandler
Association for usethisHandler
To deal withthisMessage
.- If this
Handler
isasynchronousIs sentAll of the messagesAre allasynchronous.uptimeMillis
Parameters forMessage execution time.Executed immediatelyFor theSystemClock.uptimeMillis()
.Delay to performFor theSystemClock.uptimeMillis() + delayMillis
,Send at specified timeFor theThe specified
.Queue messages to the front of the message queueFor the0
.MessageQueue
Add message related introduction, seeTripartite library -Handler source parsing -MessageQueue- Add Message.
post-Callback
post()
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
Copy the code
postAtTime()
public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
public final boolean postAtTime(@NonNull Runnable r, @Nullable Object token, long uptimeMillis) {
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
Copy the code
postDelayed()
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
public final boolean postDelayed(@NonNull Runnable r, @Nullable Object token, long delayMillis) {
return sendMessageDelayed(getPostMessage(r, token), delayMillis);
}
Copy the code
postAtFrontOfQueue()
public final boolean postAtFrontOfQueue(@NonNull Runnable r) {
return sendMessageAtFrontOfQueue(getPostMessage(r));
}
Copy the code
The above methods, which perform the specified Callback task, are implemented by Runnable. The Runnable is wrapped as a Message by getPostMessage() and then sent by calling the corresponding Message sending method.
Let’s look at the implementation of the getPostMessage() method.
getPostMessage()
private static Message getPostMessage(Runnable r) {
// Get a new Message using reuse
Message m = Message.obtain();
// Save the Runnable to the Message callback
m.callback = r;
return m;
}
@UnsupportedAppUsage
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
return m;
}
Copy the code
The getPostMessage() method, which uses the reuse mechanism to get the new Message and stores the Runnable in the Message’s callback.
summary
- Send a messageDivided into
send-Message
,post-Callback
.post-Callback
The bottom layer is also throughsend-Message
Send (willRunnable
Save toMessage
thecallback
).- through
handler
The message that is sent will eventually be sentthisMessage
andthisHandler
Association for usethisHandler
To deal withthisMessage
.- If this
Handler
isasynchronousIs sentAll of the messagesAre allasynchronous.
Distribution of the Message
When the looper.loop () method is turned on and the Next () method of the Looper MessageQueue returns a Message, the Handler’s dispatchMessage() method is called as follows.
Loop->loopOnce()
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
Message msg = me.mQueue.next(); // might block.// Call Handler to distribute the messagemsg.target.dispatchMessage(msg); . }Copy the code
Let’s look at the Handler’s dispatchMessage() method.
dispatchMessage()
Handler->dispatchMessage()
public void dispatchMessage(@NonNull Message msg) {
if(msg.callback ! =null) {
/ / Callback processing
handleCallback(msg);
} else {
/ / the Message processing
if(mCallback ! =null) {
// Handler's Callback is not null; it takes precedence.
if (mCallback.handleMessage(msg)) {
// Returns true, indicating that the handler Callback has been processed and no longer needs handleMessage() processing.
return; }}// Handle with the handleMessage methodhandleMessage(msg); }}Copy the code
The dispatchMessage() method, for sending messages, is divided into Callback processing, Message processing, and Message processing first handler Callback processing, handleMessage() method processing.
Description:
dispatchMessage()
Methods forpublic
andnotfinal
, so it can beoverwrite, in general,Don’t overwriteThis method.
Let’s first look at the handleCallback() method that handles Callback.
handleCallback()
private static void handleCallback(Message message) {
// Call callback.run() to the runnable.run() method
message.callback.run();
}
Copy the code
The handleCallback() method is executed directly by calling the Run () method of message’s callback (i.e. Runnable).
Next we’ll look at the Handler.callback class, which handles Message first, and the handleMessage() method, which handles Message second.
Handler Callback class
public interface Callback {
/ * * *@returnTrue if no further processing is required. * /
boolean handleMessage(@NonNull Message msg);
}
Copy the code
If handler.mcallback has a set value, it takes precedence, and the handleMessage() method returns true, then handleMessage() method processing is no longer required.
handleMessage()
public void handleMessage(@NonNull Message msg) {}Copy the code
The handleMessage() method, for processing messages, can be distinguished by the what value of the Message to implement its own logic.
Description:
handleMessage()
Methods forpublic
andnotfinal
, so it can beoverwrite, in general,overwriteThis method.
summary
- distribution
Message
It is throughHandler
thedispatchMessage()
methodsDistributed processing.- distribution
Message
It is divided intoTo deal withCallback
,To deal withMessage
.2.1. Handle Callback by directly calling the run() method of Callback (i.e. Runnable). 2.2. The handler Callback takes precedence over the handleMessage() method. 3. Both dispatchMessage() and handleMessage() methods can be overridden, usually just the handleMessage() method.
Remove Messages and Callbacks
removeMessages()
public final void removeMessages(int what) {
mQueue.removeMessages(this, what, null);
}
public final void removeMessages(int what, @Nullable Object object) {
mQueue.removeMessages(this, what, object);
}
Copy the code
removeCallbacks()
public final void removeCallbacks(@NonNull Runnable r) {
mQueue.removeMessages(this, r, null);
}
public final void removeCallbacks(@NonNull Runnable r, @Nullable Object token) {
mQueue.removeMessages(this, r, token);
}
Copy the code
removeCallbacksAndMessages()
public final void removeCallbacksAndMessages(@Nullable Object token) {
mQueue.removeCallbacksAndMessages(this, token);
}
Copy the code
The removeXX method of MessageQueue is used to remove Callbacks specifying what Message or runnable.
Description:
MessageQueue
For information about removing messages, seeTripartite library -Handler source parsing -MessageQueue- Remove Message.
summary
Whether there are Messages and Callbacks
hasMessages()
public final boolean hasMessages(int what) {
return mQueue.hasMessages(this, what, null);
}
Copy the code
hasCallbacks()
public final boolean hasCallbacks(@NonNull Runnable r) {
return mQueue.hasMessages(this, r, null);
}
Copy the code
hasMessagesOrCallbacks()
public final boolean hasMessagesOrCallbacks(a) {
return mQueue.hasMessages(this);
}
Copy the code
All of the above methods are used to determine whether there are any Callbacks specifying what or runnable by calling MessageQueue’s hasMessages method.
Description:
MessageQueue
Is there any information about it? Please check it outTripartite library -Handler source parsing -MessageQueue- Whether there is a Message.
summary
other
getMessageName()
public String getMessageName(@NonNull Message message) {
if(message.callback ! =null) {
// Is a Callback type that returns the class name of this Callback (that is, Runnable).
return message.callback.getClass().getName();
}
// Is of type Message, which returns the hexadecimal value of what for this Message.
return "0x" + Integer.toHexString(message.what);
}
Copy the code
Gets the string representing the specified Message name. By default, Callback returns the class name of the Callback (i.e., Runnable), and Message returns the hexadecimal of what of the Message.
getLooper()
@NonNull
public final Looper getLooper(a) {
return mLooper;
}
Copy the code
Gets the Looper object for this Handler
dump()
public final void dump(@NonNull Printer pw, @NonNull String prefix) {
pw.println(prefix + this + "@" + SystemClock.uptimeMillis());
if (mLooper == null) {
pw.println(prefix + "looper uninitialized");
} else {
mLooper.dump(pw, prefix + ""); }}Copy the code
Dump the state of Looper for debugging. If Looper is empty, print it, otherwise Looper’s dump() method is called.
Description:
Looper
For an introduction to dump, seeOther stars -.