在Android系统中,关于消息的处理几乎随处可见。提到消息处理,很自然就会想到消息的发送,消息的存储以及消息的处理这三个方面。
Android系统的消息机制与thread,looper,handler,messagequeue,message这几个类是分不开的,此外还有一个runnalbe类,其实,它最终也会被封装为message。下面首先介绍这几个类以及他们之间的关系,然后按照消息的发送,消息的存储,以及消息的处理来分析。
一、各个对象的简单介绍
thread:在多线程运行环境里,代码段的执行都是线程相关的,中断处理例程除外,它是工作于中断上下文的。Android基于linux,linux本身支持多线程。而我们的looper,handler,messagequeue,message这些对象都是寄宿在某个线程里面的。搞清楚这一点也有利于我们后面理解handler的处理到底是在哪个线程里完成的。
looper:顾名思义,实现一个循环动作。因为通常我们在实现一个线程时会让它做一个无限循环,在循环中处理各种不同的事务。looper的作用就是实现宿主线程的消息循环,后面的代码分析中会看到这一点。它负责从messagequeue中取出消息,然后根据消息指定的handler或者callback来处理这条消息。
messagequeue:消息队列就是存储消息的地方,它利用链表的方法来管理消息,looper就是从这里来获取消息的。
message:单条的消息。里面包含了消息类型,参数,标志位和处理者等等信息,后面代码分析中会详细讲到。
runnable:被封装成消息后发送到消息队列,最终会调用到它的run()方法。
相关的源文件:
HandlerThread.java(继承自java.lang.thread类)
Looper.java
MessageQueue.java
Message.java
Runnable.java
二、代码分析(以Audioservice.java中的AudioHandler为例)
首先看看我们的信使message是如何定义的:
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;
public int arg1;
public int arg2;
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;
/*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;
比较重要的几个变量都标识出来了,what用来对消息进行分类,通常在handler中处理时会使用switch(what) case what:来处理.arg1和arg2就是消息里的参数,作什么用可以自行定义。flags用来指出消息是否在使用中,是否为异步消息。when用来指明消息何时被处理,这样就使消息的处理更加灵活了。handler就是消息的处理者。callback是消息处理的另一种方式,当消息中指定了callback,则直接调用callback的run()方法来处理消息,不会再交给handler处理。等分析到后面这一点就会很清晰了。
再来看看thread是如何创建的:
在AudioService的构造函数中(AudioService是在System Server中实例化的,可以参考Android启动流程),调用
public AudioService(Context context) {
mContext = context;
……
createAudioSystemThread();
……
}
private void createAudioSystemThread() {
mAudioSystemThread = new AudioSystemThread();
mAudioSystemThread.start();
waitForAudioHandlerCreation();
}
首先创建一个AudioSystemThread,继承自Thread类(handlerthread也是继承这个类,可以认为AudioSystemThread只是给handlerthread另取了个名字),在调用start之后就会进入它的run()方法,通常,run()里面都会有一个无限循环,我们平时创建线程的时候大多数都是这么使用的,在线程里面做无限循环来处理事情。
/** Thread that handles native AudioSystem control. */
private class AudioSystemThread extends Thread {
AudioSystemThread() {
super("AudioService");
}
@Override
public void run() {
// Set this thread up so the handler will work on it
Looper.prepare();
synchronized(AudioService.this) {
mAudioHandler = new AudioHandler();
// Notify that the handler has been created
AudioService.this.notify();
}
// Listen for volume change requests that are set by VolumePanel
Looper.loop();
}
}
在这个里面,thread已经创建好了,几大角色同时登场, looper出现了, handler也有了,还有message和messagequeue不见踪影。接着看:
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));
}
在prepare的时候new了一个looper对象了,看看looper的构造函数:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread();
}
到现在为止,另一个重要角色MessageQueue也出现了,最后在run()函数中调用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.recycle();
}
}
这里面有一个for无限循环,上面也提过,一般我们创建一个线程的时候会利用无限循环来处理事务,这个无限循环就是在AudioSystemThread的run()函数中。looper的循环也不复杂,它要做的事情就是从messagequeue中取出消息,然后调用消息指定的target的dispatchMessage()函数。
还记得上面说过这个target其实就是一个handler,自然dispatchMessage()就是在handler中定义的:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
从上面可以看出,主要有三个执行分支,如果定义了callback,那么就调用handleCallback()来处理消息,handleMessage不会执行,这个callback其实是一个Runnable实例,它是一个接口类,在使用它的时候,最终会调用它的run()函数;如果没有定义callback,那么就会走到else分支,如果定义了mCallback,就会调用它的handleMessage()来处理,mCallback是什么呢?从它的成员函数也大概能猜到也是一个handler,怎么来的?在后面handler的构造函数中就会看到;如果没有定义mCallback或者handleMessage()返回值为0,则调用targe,即当前实例handler的handleMessage()。
handler的构造函数有4个:
public Handler(){
……
mLooper = Looper.myLooper();
……
mQueue = mLooper.mQueue;
mCallback = null;
}
public Handler(Callback callback){
……
mLooper = Looper.myLooper();
……
mQueue = mLooper.mQueue;
mCallback = callback;
}
public Handler(Looper looper) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = null;
}
public Handler(Looper looper, Callback callback) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
}
在创建handler时,如果没有指定looper,那么这个looper就是当前线程的looper,之后looper取出消息并调用handler的handleMessage()方法来处理消息时,都是运行在looper所在的线程上下文中。如果指令了looper,则消息的处理会在指定的looper所在线程上下文中进行。所以,looper是线程相关的,looper决定了消息在哪个线程里处理。
在实现一个handler时,handleMessage是需要用户根据自己的需要重写的一个函数,例如上面的AudioHandler:
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SET_DEVICE_VOLUME:
setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
break;
case MSG_SET_ALL_VOLUMES:
setAllVolumes((VolumeStreamState) msg.obj);
break;
case MSG_PERSIST_VOLUME:
persistVolume((VolumeStreamState) msg.obj, msg.arg1, msg.arg2);
break;
至此,各个对象基本介绍完了。而且关于消息的处理上面也有说过,looper通过queue.next获取消息,然后调用handler的dispatchMessage()来处理消息,但是消息从何而来呢?下面就来说说消息的发送:
当我们需要handler来完成某件事情时,首先当然是要往消息队列里发送消息,看看AudioHandler的实现:
// Post message to set system volume (it in turn will post a message
// to persist).
sendMsg(mAudioHandler,
MSG_SET_DEVICE_VOLUME,
SENDMSG_QUEUE,
device,
0,
streamState,
0);
}
这种方式是直接发送消息,事先并不构建消息实例,消息实例的构造放在这种类型的sendMsg()函数中(sendMsg也有很多个重载同名函数):
private static void sendMsg(Handler handler, int msg,
int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
if (existingMsgPolicy == SENDMSG_REPLACE) {
handler.removeMessages(msg);
} else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
return;
}
handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
}
创建message的接口就是这个obtainMessage():
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
{
return Message.obtain(this, what, arg1, arg2, obj);
}
紧接着看Message类的obtain:
public static Message obtain(Handler h, int what,
int arg1, int arg2, Object obj) {
Message m = obtain();
m.target = h;
m.what = what;
m.arg1 = arg1;
m.arg2 = arg2;
m.obj = obj;
return m;
}
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}
消息的target就是传递进来的handler。
前面都是在说消息是如何创建出来的,现在接着发送消息的地方来分析:
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
直接往队列里提交一条消息。接下来looper就会取出该消息并处理。
还有runnable没有说到,通常,runnable是这样使用的:
handler.post(new Runnable() {
public void run() {
mCallback.run(Future2Task.this);
}
});
调用handler的post接口,在里面实例化一个runnable对象,重写它的run()函数。
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
将message的callback赋值为r,这样,在前面的dispatchMessage()中,就会调用handlecallback(m)了:
private static void handleCallback(Message message) {
message.callback.run();
}
非常简单,直接调用run()函数。
三、总结
1.looper是线程相关的,一个线程最多只能创建一个looper,前面的分析中没有说,仔细研究looper的创建就会发现这一点。
2.handler的消息发往哪个looper,消息就会在looper的那个线程中得到处理。在构造handler的时候,如果没有指定looper,那么默认就是在创建handler对象的 线程中处理,如果指定了另外一个线程的looper,那么消息就在另外一个looper所在线程中处理。
3.looper从messagequeue中获取消息时,如果没有消息会睡眠等待,这是通过native层的进程通信FIFO实现的。