android消息机制重温

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,或者当Looperquit方法调用时,MessageQueue会被标记成退出状态,next方法返回null,当没有消息时,会一直阻塞,当next有消息时,会调用msg.target.dispatchMessage(msg),也就是HandlerdispatchMessage()方法,所以HandlerdispathMessage()会在Looperloop()方法中执行,也就在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方法仅仅是向消息队列插入一条消息。而待MessageQueuenext方法返回给Looper时,Looper会调用HandlerdispathMessage方法,这时就到了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
如果callbacknull,就检查mCallBack是否为null,如果不为null,就调用mCallBackhandleMessage()方法,那么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的构造方法传入。
最后如果callbackmCallBack都为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对象,将HandlerLooper以及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()方法中不断从MessageQueuenext方法中取出message,如果消息队列中没有消息,就一直阻塞,如果有消息,就调用handlerdispatchMessage方法,dispatchMessage方法中最后调用HandlerhandleMessage方法

猜你喜欢

转载自blog.csdn.net/camthu/article/details/81173065
今日推荐