在日常开发和学习中,我们肯定都会接触到Android消息机制。我们知道,在非UI线程中不能直接更新UI,一般我们都是在非UI线程中通过Handler发送一条消息来更新UI。通过Handler可以将任务切换到Handler所在的线程中。Android消息机制主要是指Handler的运行机制,Handler的运行需要和MessageQueue和Looper配合才能完成。可能有人会问:我在Activity新建一个Handler对象,并没有看到MessageQueue和Looper,也照样可以使用Android消息机制啊。其实在启动应用的时候,在主线程中已创建Looper对象,并开始轮询MessageQueue,判断MessageQueue中是否有消息,具体的方式我们后面会讲解。在了解Android消息机制的细节前,我们最好还是先了解Android消息机制的总体框架,心中有个总体框架图,然后再去深入的了解其内部的具体实现。
一,总体框架
上面提到,Android消息机制中有三个角色,分别是:Handler、Looper、MessageQueue(虽然我们叫消息队列,实际上它的实现是链表),其中MessageQueue是存在于Looper中的,而且每个线程只能有一个Loop而对象,但是可以有多个Handler对象,这也是为什么我们可以在主线程创建多个Handler对象。Handler扮演的是消息的传递者以及消息的处理者,Looper负责消息的轮询,MessageQueue负责存储Handler传递过来的消息。以主线程为例,子线程通过主线程中的Handler对象,传递一条消息,这条消息被传递到Looper中的MessageQueue中,然而,Looper中有个方法会一直轮询,判断MessageQueue中有没有消息,当发现有消息的时候,会根据这条消息的target(Handler对象)属性来判断这条消息交给哪个Handler来处理。整个一个流程就是这样的,给出个流程图帮助大家理解:
二,分步解析
我们将上面的流程图分成两步:
1,生成一条消息,通过Handler将消息存入Looper中的MessageQueue中。
通常,我们通过Handler创建一条消息并发送的形式是这样的:myHandler.obtainMessage(UPDATE_TEXTVIEW,msg).sendToTarget();这条语句包含两个操作:创建一条消息:发送这条消息,将消息加入MessageQueue中。当然也可以将连个操作分开写,比如写成这样:
Message ms = myHandler.obtainMessage(UPDATE_TEXTVIEW,msg);
ms.sendToTarget();
两种方式看个人习惯,喜欢哪种就写成哪种吧。我们现在通过源码来看下具体的实现是怎样的。首先是Handler的obtainMessage(int what,Object obj)方法,其他的obtainMessage()都差不多,有兴趣的可以去看下,这里我们只看obtainMessage(int what,Object obj)方法。
public final Message obtainMessage(int what, Object obj)
{
return Message.obtain(this, what, obj);
}
//obtainMessage(int what,Object obj)会调用Message
//的obtain(Handler h, int what, Object obj)方法,我们看
//下obtain()方法的具体实现
public static Message obtain(Handler h, int what, Object obj) {
Message m = obtain();
m.target = h;
m.what = what;
m.obj = obj;
return m;
}
//在obtain(Handler h, int what, Object obj)方法中会创建一
//个消息,然后初始化消息的target、what等属性。这里提下,创
//建Message对象m时并没有直接new一个Message对象,而是通
//过Message.obtain()方法来获得Message对象,这是因
//为Message.obtain()方法会先判断消息池里面有没有消息,这样提高
//消息的复用,避免每次都创建Message对象。
到这,我么可以发现创建消息还有另一种方法,比如:
Message m = Message.obtain(myHandler,UPDATE_TEXTVIEW,msg);
m.sendToTarget();
了解消息的创建后,我们再看下消息是怎样被添加到MessageQueue中的。我们看Message的sendToTarget()方法。
public void sendToTarget() {
target.sendMessage(this);
}
//在前面我们知道target就是Handler对象,这个对象也是
//在Message.obtain(Handler h,int what, Object obj)方法中
//初始化的,我们看下Handler的sendMessage(Message msg)方法
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}
//sendMessage(Message msg)最终会调
//用sendMessageAtTime(Message msg, long uptimeMills)
//方法,在此方法中的mQueue就是我们最终存放消息的地方.我们看
//下mQueue是在哪初始化的,当我们初始化Handler对象,没有传
//入Looper对象时,mQueue是这样被初始化的:
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;
}
/**我们可以看到:mQueue指向的是Looper中的mQueue对象,这也是上面框架图中为什么将MessageQueue画在Looper中。至于具体的mLooper对象是
怎样得到,下一遍文章我会具体讲解,这次我们主要是理清整体的一个框架。好了,接着上面继续,在sendMessageAtTime(Message msg,
long uptimeMills)中会调用enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis),在这个方法中通过queue.enqueueMessage(msg, uptimeMillis)最终才会将消息存入MessageQueue。
**/
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
2,从MessageQueue中取出消息,然后将消息交给特定的Handler对象处理。
在Looper 的loop()方法中,有个for循环语句,将MessageQueue中的表头Message取出,然后将叫给该Message的Handler对象处理。我们看下Looper.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();
}
}
我们主要关注for()语句中的前半段,”Message msg = queue.next()”从消息队列中取出消息,”msg.target.dispatchMessage(msg)”通过Message的target对象处理这条消息。然后我们看下Handler.dispatchMessage(Message msg)方法。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
//这里就是分发消息该怎么处理了,如果之前是通
//过Handler.post(Runnable r)的方式创建消息时,比如这样
myHandler.post(new Runnable() {
@Override
public void run() {
//处理消息
}
});
/**这个时候在dispatchMessage(Message msg)中,“msg.callback != null” 条件就成立,看下handCallback(Message msg)方法你会发现,最终就会调用你创建消息时传递的Runnable的run()方法。而mCallBack变量是通过Handler(Callback callback)、Handler(Callback callback, boolean async)、Handler(Looper looper, Callback callback, boolean async)、Handler(Looper looper, Callback callback)构造方法创建Handler对象时传递进的Callback对象。
**/
//如果 “ msg.callback == null” 和 “ Callback == null”
//那么久会调用handleMessage(msg)方法,这个方法在Handler中是
//个空方法,所以一般我们会重写这个方法来处理相应的操作(比如在主
//线程中更新UI)。
整个一个流程就是这样了,可能还有几个疑问,Android主线程中的Looper是什么时候被关键,Looper.loop()方法又是什么时候被调用的呢。要回答这个,我们就要看ActivityThread的main()方法,在main()方法中有“Looper.prepareMainLooper();”这条语句就为主线程创建了Looper对象,而“Looper.loop();”就开始轮询MessageQueue了。
三,总结
Android消息机制的整个一个流程就是这样了,大家可以对照上面的图,然后参照源码学习下。在Android消息机制中还有很多细节没有提到,比如message是怎么插入MessageQueue的,其中的算法是怎样的?Looper对象是如何存储的?这些在这都没有深入,以后会单独写篇Looper相关的博文,大家一起交流学习。