1.Message:消息对象,可通过Bundle存储数据及Runable存储业务逻辑。
Message的属性:
long when;
Handler target;
Runnable callback;
2.Handler:发送,分发及处理Message。
Handler的属性:
MessageQueue mQueue;
Looper mLooper;
Callback mCallback;
3.MessageQueue:消息队列,保存Handler发送的消息。
4.Looper:循环从MessageQueue中读取消息交给Handler分发。
Looper的属性:
MessageQueue mQueue;
Thread mThread;
5.ThreadLocal:保证每一个Thread中只有一个Looper。
1.post(Runnable r):发送一个存储了业务逻辑的Message
2.postAtTime(Runnable r, long uptimeMillis):可设置“精确”时间,在你设置的这个时间之前,不会被MessageQueue next()出来给Looper
3.postAtTime(Runnable r, Object token, long uptimeMillis)
4.postDelayed(Runnable r, long delayMillis):发送延迟消息,内部调用是这样的sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)
5.postAtFrontOfQueue(Runnable r):发送一个排在队列之前的Message,也就是说不管发送这个Message之前MessageQueue中有多少Message,下一个被处理的就是现在发送的消息。
6.sendMessage(Message msg)
7.sendEmptyMessage(int what)
8.sendEmptyMessageDelayed(int what, long delayMillis)
9.sendEmptyMessageAtTime(int what, long uptimeMillis)
10.sendMessageDelayed(Message msg, long delayMillis)
11.sendMessageAtTime(Message msg, long uptimeMillis)
12.sendMessageAtFrontOfQueue(Message msg)
在Looper源码注释中有这么一段告诉了我们在普通Thread中怎么去使用Looper来建立Handler消息机制,我加入了Callback回调,以便下面的处理流程分析
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();//准备Looper
Callback callback = new Callback(){
public boolean handleMessage(Message msg){
return false;
}
};
mHandler = new Handler(callback) {//实例化Hanlder
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();//开启循环读取消息
}
}
发送消息的函数有很多,这里以post()函数为例子
mHnalder.post(new Runable(){
public void run(){
Log.d("tag_log","Runable执行了");
}
})
发送一个Runable消息就是这样的了,接下来看下post()干了些什么:
public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
/**将Runable赋值给Message**/
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();//从消息池中获取一个Message对象
m.callback = r;
return m;
}
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);
}
/**将Message压入MessageQueue消息队列**/
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;//记录发消息的Handler,自己发的消息自己分发自己处理
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
post()做了3件事情
1. 用Message包装Runable
2. 绑定发送Message的Hanlder对象
3. 将消息压入MessageQueue
从源码可以看出,不管事用post还是send去发送消息,最后都是将一个Message压入到MessageQueue。到此,消息的发送就已经结束了。那么是谁来从MessageQueue中拿Message又交给谁去处理呢?
在建立消息机制的时候有这么一段代码
Looper.loop();//开启循环读取消息
这里就是Message分发的源头了,来看下它到底干了些什么
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;
...
/**死循环不断读取及分发Message**/
for (;;) {
Message msg = queue.next(); //从队列中读取消息
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
/**将Message交给Handler分发**/
msg.target.dispatchMessage(msg);
...
/**消息处理结束,进行回收**/
msg.recycleUnchecked();
}
}
loop()就做了3件事情
1. 读取消息
2. 将Message给msg.target分发
3. 将处理完成的Message回收
消息分发就在这里msg.target.dispatchMessage(msg),在enqueueMessage()函数中我们知道msg.target就是发送这个Message的Hanlder对象,所以到最后Message的分发还是Handler自己来处理的,好吧那我们来看下它是怎么分发消息的?
public void dispatchMessage(Message msg) {
if (msg.callback != null) {/**Message的Runable不为null,则直接运行Runable对象**/
handleCallback(msg);
} else {/**Message的Runable为null**/
if (mCallback != null) {/**若Handler的Callback不为null,则将消息交给Callback处理**/
if (mCallback.handleMessage(msg)) {
/**如果Runable处理该消息之后返回true,则结束该消息的分发**/
return;
}
}
/**如果Runable处理该消息之后返回false,则继续将消息传递给Handler的handleMessage()处理,结束该消息的分发**/
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
看到了吧,到最后Message还是Handler自己来处理的。印证了enqueueMessage()中的那句注释,自己发送的消息自己分发自己处理。
在查看源码的过程中,我发现Handler中是使用SystemClock.uptimeMillis()函数来获取时间,而平常我设置时间间隔一般都使用System.currentTimeMillis(),问题来了:
1. 那这两种方法有何区别呢?
2. 如果在postAtTime(Runnable r, long uptimeMillis)的时候使用System.currentTimeMillis()会怎么样?
1. SystemClock.uptimeMillis()是从开机到现在的毫秒数(手机睡眠的时间不包括在内);
2. System.currentTimeMillis()是从1970年1月1日 UTC到手机当前时间的毫秒数;
但是,第2个时间,是可以通过System.setCurrentTimeMillis修改的,那么,在某些情况下,一但被修改,时间间隔就不准了。
Handler handler = new Handler();
handler.postAtTime(new Runnable() {
@Override
public void run() {
Log.d("tag_log", "Runnable执行了");
}
},SystemClock.uptimeMillis());
Log正常打印出来了。
Handler handler = new Handler();
handler.postAtTime(new Runnable() {
@Override
public void run() {
Log.d("tag_log", "Runnable执行了");
}
},System.currentTimeMillis());
等了很久Log就是打印不出来了。这是为什么呢?
最后跟踪源码发现传入的参数uptimeMillis赋值给了Message的when属性,而在MessageQueue的next()函数中有这么一段:
Message next() {
...
for (;;) {
...
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
...
if (msg != null) {
//msg.when就是我们设置的时间
if (now < msg.when) {
...
} else {
...
msg.markInUse();
return msg;
}
} else {
...
}
}
}
也就是说,你给Message设置的时间比现在的SystemClock.uptimeMillis()时间大的话,next()函数就不会将你返回给Looper分发处理。随即我打印这两个时间做对比
tag_log: SystemClock.uptimeMillis():2546808
tag_log: System.currentTimeMillis():1461813573568
我靠System.currentTimeMillis()大太多了,所以说,如果我们在这里使用System.currentTimeMillis()的话,now < msg.when很长一段时间内都为true(在不手动System.setCurrentTimeMillis的话),这样我们发送的Message在手机不关机的几十年里也得不到执行了。我就是System.currentTimeMillis盲目使用者,幸运的是我以前只发送过延迟消息。。。。