在我们的Android开发中,我们都知道不能在主线程中做网络操作、耗时操作等。所以我们都会另开线程去执行这些操作,但是当操作结束之后我们又必须在主线程中去修改UI。而此时我们通常使用Handler来解决。
在我们使用Handler的时候就涉及了Android的消息机制。我们一起来分析一下Android的消息机制。
Android的消息机制由MessageQueue、Looper、Handler三者构成。
MessageQueue:消息队列,用来保存handler发送的消息;其使用单链表实现。MessageQueue只包含两个主要的操作即enqueueMessage和next,分别用来插入和取出一条消息并从队列中移除。MessageQueue只负责保存消息,并不处理消息。
我们在MessageQueue的源码中可以看到next()方法有如下的代码:
Message next() {
// Return here ifthe message loop has already quit and been disposed.
// This can happen if the applicationtries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount= -1; // -1 only during first iteration
int nextPollTimeoutMillis= 0;
for (;;) {
…
}
}
从中我们可以看出,next()方法中有一个死循环,如果消息队列中没有消息,那么next()方法会一直阻塞,直到有消息过来。
Looper:在主线程中使用Handler时我们一般不会涉及到Looper对象。因为在主线程中系统会默认为我们创建一个Looper对象。而在子线程中如果我们直接使用Handler会出现Can’t create handler inside thread that has not calledLooper.prepare();之所以出现这个异常是因为Handler的消息是由Looper处理的,但是我们并没有创建Loope对象。在子线程中使用Looper.prepare()即可创建Looper对象。在Looper的源码中我们通过私有的构造函数
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
我们可以看出Looper会创建一个MessageQueue对象,在上面我们已经知道了MessageQueue不会处理消息,而是由Looper对象处理的。在Looper.loop()方法的源码中
/** * 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(); } } 我们可以看出loop()方法会不断的调用MessageQueue的next()方法来查看是否有新消息。
Handler:在Handlerde 源码中我们发现我们通过Handler对象的post和send的一系列发送消息的方法最后都会通过send方法来实现。而send一系列的方法最终都会进入如下方法:
public boolean sendMessageAtTime(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); }
我们能够看出send方法其实是往消息队列中插入一条消息,而Looper对象又会通过loop()方法来调用MessageQueue对象的next()方法去获取消息,最后交给Handler的dispatchMessage方法处理。
这样Handler、MessageQueue和Looper就连同工作了。