介绍
Handler的工作主要是信息的发送和处理,信息的发送通过post和send的一系列方法(实质上都是send),
处理则是通过覆盖handleMessage方法或实现Callback接口。接下来就来看一下Handler的关键方法吧。
send 和post
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;
}
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
可以看到,post方法通过把Runnable包装成Message,保存在callback属性中。最后和send一样调用的是sendMessageAtTime方法,再转到enqueueMessage方法后,Handler调用了MessageQueue的enqueueMessage把Message插入到了事件队列之中,并将指定Message处理对象的msg.target指定为自己。
dispatchMessage
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
从对Looper的分析知道,最后是Handler的dispatchMessage处理Message。dispatchMessage对Message的处理逻辑是,先看msg是否是post的Runnable转换过来的(callback属性),如果是就直接调用其的run方法;再看Handler是否实现了Callback接口(mCallback);如果没有,或者没有处理Message,最后再调用handleMessage方法。所以可以知道实现Callback接口的优先级是比覆盖handleMessage方法高的。
我们使用handler的常规方式是通过覆盖handleMessage方法,所以我们可以使用mCallback来拦截handler的特定message。我一时也想不到这种处理方式具体的使用场景,但我感觉,这种方式对于在多个handler中处理相同的message,或者采用策略模式在不同状态下通过不同mCallback来处理message,这些情况可能会有效果。
总结
到这里Handler,Looper,MessageQueue都已经看完了,分析一下这个机制最重要的功能——切换线程,是通过哪里完成的。当Handler的send方法被调用之后,enqueueMessage方法将Message插入消息队列,由Looper处理,这个时候还是在send方法调用处所在的线程里;而Looper是与线程绑定的,当Looper调用dispatchMessage的时候,就已经在Handler定义所在的线程了;所以线程切换在MessageQueue的enqueueMessage中,Looper调用其next方法在一个线程中读,enqueueMessage在另一个线程中插入,因此在enqueueMessage和next中用synchronized给MessageQueue加了锁,防止冲突。