命令模式下的异步消息处理( Handler,Message,Looper,MessageQueue)

接受者:Handler,执行消息处理操作。请求者:Looper,调用消息的的处理方法。命令角色:Message,消息类。客户端:Thread,创建消息并绑定Handler(接受者)。 命令角色:Message Class Overview:
Defines a message containing a description and arbitrary data object that can be sent to a Handler. This object contains two extra int fields and an extra object field that allow you to not do allocations in many cases.
消息包含了消息说明和任意的数据,消息能够被发送给Handler。消息对象包含2个额外的int类型字段(arg1,arg2)和一个额外的Object类型字段(obj),可以使用这写字段存放任意的信息(一般如果是简单的int类型数据存放在arg1和arg2这2个字段中就行了)。
While the constructor of Message is public, the best way to get one of these is to call Message.obtain() or one of the Handler.obtainMessage() methods, which will pull them from a pool of recycled objects. 一般使用静态方法Message.obtain()或Handler.obtainMessage()获取实例,这样的好处是获取的实例是来自一个循环使用的消息对象池。 MessageQueue 这个类表示消息队列,一个消息队列与一个线程绑定。这个类内部是通过链表来实现队列的,根据消息的延迟执行的时间量来决定消息在队列中的位置,延迟执行的时间量越少的消息越靠前。 MessageQueue.java 代码: 消息入队列方法: final boolean enqueueMessage(Message msg, long when) { //参数when为消息的延迟时间量
........
synchronized (this) {
................ msg.when = when;
//Log.d("MessageQueue", "Enqueing: " + msg);
Message p = mMessages;
if (p == null || when == 0 || when < p.when) { //如果待入队列消息的延迟时间为0(立即执行)或比队列顶部消息的延迟时间少,则此待入队列消息放到队列顶部
msg.next = p;
mMessages = msg;
this.notify();
} else { //否则,从头遍历链表,查找到第一个延迟时间比待入队消息长的消息,将待入队消息插入这个消息之前
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
this.notify();
}
}
return true;
} 获取队列中的下一个消息:遍历消息队列,返回一个可以在当前时间处理的消息,如果找不到这样的一个消息,则阻塞当前线程,直到出现一个可以处理的消息为止。
final Message next() {
boolean tryIdle = true; while (true) {
long now;
Object[] idlers = null;
// Try to retrieve the next message, returning if found.
synchronized (this) {
now = SystemClock.uptimeMillis();
Message msg = pullNextLocked(now); //获取一个可以在当前时间处理的消息
if (msg != null) return msg; //如果有这样的消息,则返回这个消息
if (tryIdle && mIdleHandlers.size() > 0) {
idlers = mIdleHandlers.toArray();
}
}
//通过IdleHandler回调接口,提供了一个机制可以在线程为了等待可处理消息,而进入阻塞前,执行一些处理(比如生产入队一个可处理的消息)。
// There was no message so we are going to wait... but first,
// if there are any idle handlers let them know. //调用IdleHandler回调接口执行 //----------------start--------------
boolean didIdle = false;
if (idlers != null) {
for (Object idler : idlers) {
boolean keep = false;
try {
didIdle = true;
keep = ((IdleHandler)idler).queueIdle();
} catch (Throwable t) {
Log.e("MessageQueue",
"IdleHandler threw exception", t);
RuntimeInit.crash("MessageQueue", t);
} if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
}
// While calling an idle handler, a new message could have been
// delivered... so go back and look again for a pending message.
if (didIdle) {
tryIdle = false;
continue;
} //----------------end-------------- //获取当前队列顶部消息还有延迟多久才可以处理,使线程阻塞到那个时候为止 synchronized (this) {
// No messages, nobody to tell about it... time to wait!
try {
if (mMessages != null) {
if (mMessages.when-now > 0) {
Binder.flushPendingCommands();
this.wait(mMessages.when-now);
}
} else {
Binder.flushPendingCommands();
this.wait();
}
}
catch (InterruptedException e) {
}
}
}
} /**
* Callback interface for discovering when a thread is going to block
* waiting for more messages. * 当线程进入阻塞前,执行此回调接口。这个接口提供了一个机制可以在线程为了等待可处理消息,而进入阻塞前,执行一些处理(比如生产入队一个可处理的消息)。
*/
public static interface IdleHandler {
/**
* Called when the message queue has run out of messages and will now
* wait for more. Return true to keep your idle handler active, false
* to have it removed. This may be called if there are still messages
* pending in the queue, but they are all scheduled to be dispatched
* after the current time. * 当消息队列中没有可在当前时间处理的消息并且要进入阻塞等待出现可以处理的消息(比如:当前队列中所以的消息都是计划在当前时间之后执行的)时,调用此方法。 返回true,使这个接口实例保持活动;false,这个接口实例将从接口实例类表中移除(这个接口列表是每次)。
*/
boolean queueIdle();
} 请求者:Looper 这个类用于为线程执行一个消息循环。Looper的实例与一个线程绑定,但是线程默认是没有Looper对象与其绑定的,可以通过在线程上调用Looper.prepare()绑定一个Looper对象到当前线程,这后调用Looper.loop()方法执行消息循环,直到循环被停止(遇到一个target=null的消息,就会退出当前消息循环)。 public static final void loop() {
Looper me = myLooper(); //获取与当前线程绑定的Looper对象
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block 从队列中获取一个消息,如果当前队列中没有可以立即处理的消息,则阻塞当前线程,直到出现一个可以处理的消息为止
//if (!me.mRun) {
// break;
//}
if (msg != null) {
if (msg.target == null) { //遇到一个target=null的消息,就会退出当前消息循环
// No target is a magic identifier for the quit message.
return;
}
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
msg.target.dispatchMessage(msg); //处理消息
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
msg.recycle(); //回收消息对象到消息对象池
}
}
} Looper通过一个本地线程变量来实现Looper实例与线程的绑定。 private static final ThreadLocal sThreadLocal = new ThreadLocal(); 当在线程中调用prepare()时,判断当前线程是否已经有一个Looper对象与其绑定,如果有,这抛出一个异常;如果没有,则创建一个放了本地线程变量中。 public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
} 与线程绑定的消息队列也是在Looper实例创建时创建的。 private Looper() {
mQueue = new MessageQueue();
....... } 接受者:Handler
对消息的发送和处理逻辑由一个Handler类提供。一个Handler的对象是与一个线程和线程的消息队列绑定,并将消息发送到这个消息队列,处理的也是这个消息队列中的消息。
Class Overview:
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue. There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.
Scheduling messages is accomplished with the post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long), and sendMessageDelayed(Message, long) methods. The post versions allow you to enqueue Runnable objects to be called by the message queue when they are received; the sendMessage versions allow you to enqueue a Message object containing a bundle of data that will be processed by the Handler's handleMessage(Message) method (requiring that you implement a subclass of Handler).
When posting or sending to a Handler, you can either allow the item to be processed as soon as the message queue is ready to do so, or specify a delay before it gets processed or absolute time for it to be processed. The latter two allow you to implement timeouts, ticks, and other timing-based behavior.

接受者:Handler,执行消息处理操作。请求者:Looper,调用消息的的处理方法。命令角色:Message,消息类。客户端:Thread,创建消息并绑定Handler(接受者)。 命令角色:Message Class Overview:
Defines a message containing a description and arbitrary data object that can be sent to a Handler. This object contains two extra int fields and an extra object field that allow you to not do allocations in many cases.
消息包含了消息说明和任意的数据,消息能够被发送给Handler。消息对象包含2个额外的int类型字段(arg1,arg2)和一个额外的Object类型字段(obj),可以使用这写字段存放任意的信息(一般如果是简单的int类型数据存放在arg1和arg2这2个字段中就行了)。
While the constructor of Message is public, the best way to get one of these is to call Message.obtain() or one of the Handler.obtainMessage() methods, which will pull them from a pool of recycled objects. 一般使用静态方法Message.obtain()或Handler.obtainMessage()获取实例,这样的好处是获取的实例是来自一个循环使用的消息对象池。 MessageQueue 这个类表示消息队列,一个消息队列与一个线程绑定。这个类内部是通过链表来实现队列的,根据消息的延迟执行的时间量来决定消息在队列中的位置,延迟执行的时间量越少的消息越靠前。 MessageQueue.java 代码: 消息入队列方法: final boolean enqueueMessage(Message msg, long when) { //参数when为消息的延迟时间量
........
synchronized (this) {
................ msg.when = when;
//Log.d("MessageQueue", "Enqueing: " + msg);
Message p = mMessages;
if (p == null || when == 0 || when < p.when) { //如果待入队列消息的延迟时间为0(立即执行)或比队列顶部消息的延迟时间少,则此待入队列消息放到队列顶部
msg.next = p;
mMessages = msg;
this.notify();
} else { //否则,从头遍历链表,查找到第一个延迟时间比待入队消息长的消息,将待入队消息插入这个消息之前
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
this.notify();
}
}
return true;
} 获取队列中的下一个消息:遍历消息队列,返回一个可以在当前时间处理的消息,如果找不到这样的一个消息,则阻塞当前线程,直到出现一个可以处理的消息为止。
final Message next() {
boolean tryIdle = true; while (true) {
long now;
Object[] idlers = null;
// Try to retrieve the next message, returning if found.
synchronized (this) {
now = SystemClock.uptimeMillis();
Message msg = pullNextLocked(now); //获取一个可以在当前时间处理的消息
if (msg != null) return msg; //如果有这样的消息,则返回这个消息
if (tryIdle && mIdleHandlers.size() > 0) {
idlers = mIdleHandlers.toArray();
}
}
//通过IdleHandler回调接口,提供了一个机制可以在线程为了等待可处理消息,而进入阻塞前,执行一些处理(比如生产入队一个可处理的消息)。
// There was no message so we are going to wait... but first,
// if there are any idle handlers let them know. //调用IdleHandler回调接口执行 //----------------start--------------
boolean didIdle = false;
if (idlers != null) {
for (Object idler : idlers) {
boolean keep = false;
try {
didIdle = true;
keep = ((IdleHandler)idler).queueIdle();
} catch (Throwable t) {
Log.e("MessageQueue",
"IdleHandler threw exception", t);
RuntimeInit.crash("MessageQueue", t);
} if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
}
// While calling an idle handler, a new message could have been
// delivered... so go back and look again for a pending message.
if (didIdle) {
tryIdle = false;
continue;
} //----------------end-------------- //获取当前队列顶部消息还有延迟多久才可以处理,使线程阻塞到那个时候为止 synchronized (this) {
// No messages, nobody to tell about it... time to wait!
try {
if (mMessages != null) {
if (mMessages.when-now > 0) {
Binder.flushPendingCommands();
this.wait(mMessages.when-now);
}
} else {
Binder.flushPendingCommands();
this.wait();
}
}
catch (InterruptedException e) {
}
}
}
} /**
* Callback interface for discovering when a thread is going to block
* waiting for more messages. * 当线程进入阻塞前,执行此回调接口。这个接口提供了一个机制可以在线程为了等待可处理消息,而进入阻塞前,执行一些处理(比如生产入队一个可处理的消息)。
*/
public static interface IdleHandler {
/**
* Called when the message queue has run out of messages and will now
* wait for more. Return true to keep your idle handler active, false
* to have it removed. This may be called if there are still messages
* pending in the queue, but they are all scheduled to be dispatched
* after the current time. * 当消息队列中没有可在当前时间处理的消息并且要进入阻塞等待出现可以处理的消息(比如:当前队列中所以的消息都是计划在当前时间之后执行的)时,调用此方法。 返回true,使这个接口实例保持活动;false,这个接口实例将从接口实例类表中移除(这个接口列表是每次)。
*/
boolean queueIdle();
} 请求者:Looper 这个类用于为线程执行一个消息循环。Looper的实例与一个线程绑定,但是线程默认是没有Looper对象与其绑定的,可以通过在线程上调用Looper.prepare()绑定一个Looper对象到当前线程,这后调用Looper.loop()方法执行消息循环,直到循环被停止(遇到一个target=null的消息,就会退出当前消息循环)。 public static final void loop() {
Looper me = myLooper(); //获取与当前线程绑定的Looper对象
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block 从队列中获取一个消息,如果当前队列中没有可以立即处理的消息,则阻塞当前线程,直到出现一个可以处理的消息为止
//if (!me.mRun) {
// break;
//}
if (msg != null) {
if (msg.target == null) { //遇到一个target=null的消息,就会退出当前消息循环
// No target is a magic identifier for the quit message.
return;
}
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
msg.target.dispatchMessage(msg); //处理消息
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
msg.recycle(); //回收消息对象到消息对象池
}
}
} Looper通过一个本地线程变量来实现Looper实例与线程的绑定。 private static final ThreadLocal sThreadLocal = new ThreadLocal(); 当在线程中调用prepare()时,判断当前线程是否已经有一个Looper对象与其绑定,如果有,这抛出一个异常;如果没有,则创建一个放了本地线程变量中。 public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
} 与线程绑定的消息队列也是在Looper实例创建时创建的。 private Looper() {
mQueue = new MessageQueue();
....... } 接受者:Handler
对消息的发送和处理逻辑由一个Handler类提供。一个Handler的对象是与一个线程和线程的消息队列绑定,并将消息发送到这个消息队列,处理的也是这个消息队列中的消息。
Class Overview:
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue. There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.
Scheduling messages is accomplished with the post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long), and sendMessageDelayed(Message, long) methods. The post versions allow you to enqueue Runnable objects to be called by the message queue when they are received; the sendMessage versions allow you to enqueue a Message object containing a bundle of data that will be processed by the Handler's handleMessage(Message) method (requiring that you implement a subclass of Handler).
When posting or sending to a Handler, you can either allow the item to be processed as soon as the message queue is ready to do so, or specify a delay before it gets processed or absolute time for it to be processed. The latter two allow you to implement timeouts, ticks, and other timing-based behavior.