Handler处理消息 由 Handler、Message、Looper 来携手完成,那么Handler内部是如何处理消息的呢?
Message
封装了消息,消息处理对象及数据,在使用Message时建议使用Message.obtain从空消息池中获取一个空消息对象,节约内存开销。
源码如下:
public final class Message implements Parcelable {
/**
* User-defined message code so that the recipient can identify
* what this message is about. Each {@link Handler} has its own name-space
* for message codes, so you do not need to worry about yours conflicting
* with other handlers.
*/
public int what;
/**
* arg1 and arg2 are lower-cost alternatives to using
* {@link #setData(Bundle) setData()} if you only need to store a
* few integer values.
*/
public int arg1;
/**
* arg1 and arg2 are lower-cost alternatives to using
* {@link #setData(Bundle) setData()} if you only need to store a
* few integer values.
*/
public int arg2;
/**
* An arbitrary object to send to the recipient. When using
* {@link Messenger} to send the message across processes this can only
* be non-null if it contains a Parcelable of a framework class (not one
* implemented by the application). For other data transfer use
* {@link #setData}.
*
* <p>Note that Parcelable objects here are not supported prior to
* the {@link android.os.Build.VERSION_CODES#FROYO} release.
*/
public Object obj;
/**
* Optional Messenger where replies to this message can be sent. The
* semantics of exactly how this is used are up to the sender and
* receiver.
*/
public Messenger replyTo;
/**
* Optional field indicating the uid that sent the message. This is
* only valid for messages posted by a {@link Messenger}; otherwise,
* it will be -1.
*/
public int sendingUid = -1;
/** If set message is in use.
* This flag is set when the message is enqueued and remains set while it
* is delivered and afterwards when it is recycled. The flag is only cleared
* when a new message is created or obtained since that is the only time that
* applications are allowed to modify the contents of the message.
*
* It is an error to attempt to enqueue or recycle a message that is already in use.
*/
/*package*/ static final int FLAG_IN_USE = 1 << 0;
/** If set message is asynchronous */
/*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;
/** Flags to clear in the copyFrom method */
/*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
/*package*/ int flags;
/*package*/ long when;
/*package*/ Bundle data;
/*package*/ Handler target;
/*package*/ Runnable callback;
// sometimes we store linked lists of these things
/*package*/ Message next;
private static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
private static boolean gCheckRecycle = true;
/**
* 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;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
}
看到Message自身有个next引用(一个单链表数据结构),和sPool空消息池对象,一些装载数据的对象,处理消息的Handler对象,obtain方法从消息池获取一个空消息对象,如果没有的话,实例化一个。
Looper
Looper是一个消息轮询器,一直在循环查看MessageQueue里面有没有消息,如果有就获取Message的Handler对象处理消息。
源码如下:
public final class Looper {
/*
* API Implementation Note:
*
* This class contains the code required to set up and manage an event loop
* based on MessageQueue. APIs that affect the state of the queue should be
* defined on MessageQueue or Handler rather than on Looper itself. For example,
* idle handlers and sync barriers are defined on the queue whereas preparing the
* thread, looping, and quitting are defined on the 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>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
private Printer mLogging;
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
/** 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() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
/**
* Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end 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.");
}
final 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();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// 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);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// 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.recycleUnchecked();
}
}
}
在代码中可以看到静态的ThreadLocal<Looper> ,内部维护一个MessageQueue(消息队列),使用Handler之前要启动Looper,先调用prepare方法,然后调用loop方法循环消息队列,如果发现消息就拿到处理消息的Handler调用dispatchMessage(),在主线程中,Android系统启动时已经调用好了prepare和loop 感兴趣的可以看源码ActivityThread.java类。然后看最后一行代码,调用了Message的一个方法,方法如下:
/**
* Recycles a Message that may be in-use.
* Used internally by the MessageQueue and Looper when disposing of queued Messages.
*/
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
重置消息,塞进空消息池,就这么简单。
Handler
Handler是控制消息的发送和处理
Handler构造方法如下:
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: " +
klass.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;
}
Handler有很多构造方法,通常情况最后会调到这个构造,在这里面获取了当前线程的Looper MessageQueue。
发送消息代码如下:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
Handler有很多发送消息的方法,最终都会调到这个方法,把msg的执行者设为this,加入到消息队列。
刚才看到Looper.loop方法中循环获取到消息调用了dispatchMessage方法处理,方法代码如下:
/**
* 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);
}
}
msg.callback 就是使用 handler.post方法中传入的Runnable对象,然后如果为空的话就判断mCallBack,这个对象是通过Handler的构造方法传入的回调对象,如果为空则调用重写的handleMessage方法。
这就是Handle的工作流程了。