MessageQueue的工作原理
MessageQueue
就是所谓的消息队列,虽然称之为队列,但它实际上是通过一个单链表数据结构来维护消息列表列表,单链表在插入和删除上比较有优势,而MessageQueue
主要包含两个操作:插入消息enqueueMessage()
和读取消息next()
下面我们来看下MessageQueue
中的源码实现,首先是enqueueMessage()
的源码:
1boolean enqueueMessage(Message msg, long when) {
2 synchronized (this) {
3 if (mQuitting) {
4 IllegalStateException e = new IllegalStateException(
5 msg.target + " sending message to a Handler on a dead thread");
6 Log.w(TAG, e.getMessage(), e);
7 msg.recycle();
8 return false;
9 }
10
11 msg.markInUse();
12 msg.when = when;
13 Message p = mMessages;
14 boolean needWake;
15 if (p == null || when == 0 || when < p.when) {
16 // New head, wake up the event queue if blocked.
17 msg.next = p;
18 mMessages = msg;
19 needWake = mBlocked;
20 } else {
21 // Inserted within the middle of the queue. Usually we don't have to wake
22 // up the event queue unless there is a barrier at the head of the queue
23 // and the message is the earliest asynchronous message in the queue.
24 needWake = mBlocked && p.target == null && msg.isAsynchronous();
25 Message prev;
26 for (;;) {
27 prev = p;
28 p = p.next;
29 if (p == null || when < p.when) {
30 break;
31 }
32 if (needWake && p.isAsynchronous()) {
33 needWake = false;
34 }
35 }
36 msg.next = p; // invariant: p == prev.next
37 prev.next = msg;
38 }
39
40 // We can assume mPtr != 0 because mQuitting is false.
41 if (needWake) {
42 nativeWake(mPtr);
43 }
44 }
45 return true;
46 }
从enqueueMessage()
的实现来看,主要操作就是单链表的插入操作,接下来看下next()
的源码实现
1Message next() {
2 ....
3 for (;;) {
4 if (nextPollTimeoutMillis != 0) {
5 Binder.flushPendingCommands();
6 }
7
8 nativePollOnce(ptr, nextPollTimeoutMillis);
9
10 synchronized (this) {
11 // Try to retrieve the next message. Return if found.
12 final long now = SystemClock.uptimeMillis();
13 Message prevMsg = null;
14 Message msg = mMessages;
15 if (msg != null && msg.target == null) {
16 // Stalled by a barrier. Find the next asynchronous message in the queue.
17 do {
18 prevMsg = msg;
19 msg = msg.next;
20 } while (msg != null && !msg.isAsynchronous());
21 }
22 if (msg != null) {
23 if (now < msg.when) {
24 // Next message is not ready. Set a timeout to wake up when it is ready.
25 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
26 } else {
27 // Got a message.
28 mBlocked = false;
29 if (prevMsg != null) {
30 prevMsg.next = msg.next;
31 } else {
32 mMessages = msg.next;
33 }
34 msg.next = null;
35 if (DEBUG) Log.v(TAG, "Returning message: " + msg);
36 msg.markInUse();
37 return msg;
38 }
39 } else {
40 // No more messages.
41 nextPollTimeoutMillis = -1;
42 }
43
44 ....
可以发现next方法中包含一个无限循环的方法,如果消息队列中没有消息,就一直阻塞在这里,当有新信息到来或者延迟消息延迟时间到了,next就会返回这条消息并将其从列表中删除。
Looper的工作原理
Looper
在消息机制中扮演消息泵的角色,也就是它会从消息队列中不断取出消息,如果消息队列中没有消息,就一直阻塞在那里。
1 private Looper(boolean quitAllowed) {
2 mQueue = new MessageQueue(quitAllowed);
3 mThread = Thread.currentThread();
4 }
从Looper
的构造方法中可以看出,在构造方法中它会创建一个MessageQueue
对象。
既然Handler
的工作需要Looper
,那么如何在子线程中创建Looper
对象
1 class LooperThread extends Thread {
2 public Handler mHandler;
3
4 public void run() {
5 Looper.prepare();
6
7 mHandler = new Handler() {
8 public void handleMessage(Message msg) {
9 // process incoming messages here
10 }
11 };
12
13 Looper.loop();
14 }
15
16 private static void prepare(boolean quitAllowed) {
17 if (sThreadLocal.get() != null) {
18 throw new RuntimeException("Only one Looper may be created per thread");
19 }
20 sThreadLocal.set(new Looper(quitAllowed));
21 }
可以看出Looper.prepare()
会生成一个Looper
对象,并将Looper
存储到线程存储器ThreadLocal
中。
现在来看下Looper
中最主要的一个方法loop()
的代码实现:
1 public static void loop() {
2 final Looper me = myLooper();
3 if (me == null) {
4 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
5 }
6 final MessageQueue queue = me.mQueue;
7
8 // Make sure the identity of this thread is that of the local process,
9 // and keep track of what that identity token actually is.
10 Binder.clearCallingIdentity();
11 final long ident = Binder.clearCallingIdentity();
12
13 for (;;) {
14 Message msg = queue.next(); // might block
15 if (msg == null) {
16 // No message indicates that the message queue is quitting.
17 return;
18 }
19
20 // This must be in a local variable, in case a UI event sets the logger
21 Printer logging = me.mLogging;
22 if (logging != null) {
23 logging.println(">>>>> Dispatching to " + msg.target + " " +
24 msg.callback + ": " + msg.what);
25 }
26
27 msg.target.dispatchMessage(msg);
28
29 if (logging != null) {
30 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
31 }
32
33 // Make sure that during the course of dispatching the
34 // identity of the thread wasn't corrupted.
35 final long newIdent = Binder.clearCallingIdentity();
36 if (ident != newIdent) {
37 Log.wtf(TAG, "Thread identity changed from 0x"
38 + Long.toHexString(ident) + " to 0x"
39 + Long.toHexString(newIdent) + " while dispatching to "
40 + msg.target.getClass().getName() + " "
41 + msg.callback + " what=" + msg.what);
42 }
43
44 msg.recycleUnchecked();
45 }
46 }
loop()
方法内部是一个死循环,只有当MessageQueue.next()
返回为null
,或者当Looper
的quit
方法调用时,MessageQueue
会被标记成退出状态,next
方法返回null
,当没有消息时,会一直阻塞,当next
有消息时,会调用msg.target.dispatchMessage(msg)
,也就是Handler
的dispatchMessage()
方法,所以Handler
的dispathMessage()
会在Looper
的loop()
方法中执行,也就在Looper
所在的线程中执行。
Handler的工作原理
Handler
的主要工作就是发送消息和接收消息。其中发送消息对应send的一系列方法
和post的一系列方法
,而post方法
其实也是调用的send
方法。我们来看下send
方法的实现原理:
1 public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
2 MessageQueue queue = mQueue;
3 if (queue == null) {
4 RuntimeException e = new RuntimeException(
5 this + " sendMessageAtTime() called with no mQueue");
6 Log.w("Looper", e.getMessage(), e);
7 return false;
8 }
9 return enqueueMessage(queue, msg, uptimeMillis);
10 }
可以看出send
方法仅仅是向消息队列插入一条消息。而待MessageQueue
的next
方法返回给Looper
时,Looper
会调用Handler
的dispathMessage
方法,这时就到了Handler
处理消息阶段了。来看下dispathMessage
方法的实现:
1 public void dispatchMessage(Message msg) {
2 if (msg.callback != null) {
3 handleCallback(msg);
4 } else {
5 if (mCallback != null) {
6 if (mCallback.handleMessage(msg)) {
7 return;
8 }
9 }
10 handleMessage(msg);
11 }
12 }
那么Handler
的消息处理流程就很清晰了,首先检查callback
是否null
,不为null
,就交给callback
处理,那么callback
是怎么来的呢?
1 public final boolean postAtTime(Runnable r, long uptimeMillis)
2 {
3 return sendMessageAtTime(getPostMessage(r), uptimeMillis);
4 }
5
6 private static Message getPostMessage(Runnable r) {
7 Message m = Message.obtain();
8 m.callback = r;
9 return m;
10 }
可以看出callback
是调用post
方法出入的Runnable
。
如果callback
为null
,就检查mCallBack
是否为null
,如果不为null
,就调用mCallBack
的handleMessage()
方法,那么mCallBack
又是从哪里传入的呢?
1 public Handler(Callback callback, boolean async) {
2 mLooper = Looper.myLooper();
3 if (mLooper == null) {
4 throw new RuntimeException(
5 "Can't create handler inside thread that has not called Looper.prepare()");
6 }
7 mQueue = mLooper.mQueue;
8 mCallback = callback;
9 mAsynchronous = async;
10 }
11
12 public interface Callback {
13 public boolean handleMessage(Message msg);
14 }
CallBack
原来是Handler
内部的一个接口,通过Handler
的构造方法传入。
最后如果callback
和mCallBack
都为null
,就调用handleMessage()
。
android消息机制流程
好了,现在来捋捋android消息机制的整个流程
通过下面这段在子线程中创建handler的代码,其实android消息机制的整个流程其实已经很清楚了。
1class LooperThread extends Thread {
2 public Handler mHandler;
3
4 public void run() {
5 Looper.prepare();
6
7 mHandler = new Handler() {
8 public void handleMessage(Message msg) {
9 // process incoming messages here
10 }
11 };
12
13 Looper.loop();
14 }
首先Looper.prepare()
会生成Looper
对象,并且在Looper
的构造方法中创建一个MessageQueue
对象,并将Looper对象存储到当前线程的Threadlocal中。
1 private static void prepare(boolean quitAllowed) {
2 if (sThreadLocal.get() != null) {
3 throw new RuntimeException("Only one Looper may be created per thread");
4 }
5 sThreadLocal.set(new Looper(quitAllowed));
6 }
其次创建Handler
对象,通过Looper.myLooper()
取出当前线程ThreadLocal
中存储的Looper
对象,将Handler
与Looper
以及MessageQueue
关联起来
1 public Handler(Callback callback, boolean async) {
2 ...
3 mLooper = Looper.myLooper();
4 if (mLooper == null) {
5 throw new RuntimeException(
6 "Can't create handler inside thread that has not called Looper.prepare()");
7 }
8 mQueue = mLooper.mQueue;
9 mCallback = callback;
10 mAsynchronous = async;
11 }
12
13 public static @Nullable Looper myLooper() {
14 return sThreadLocal.get();
15 }
最后一步就是调用Looper.loop()
方法,loop()
方法中不断从MessageQueue
的next
方法中取出message
,如果消息队列中没有消息,就一直阻塞,如果有消息,就调用handler
的dispatchMessage
方法,dispatchMessage
方法中最后调用Handler
的handleMessage
方法