一、先看下他们各自的用途
Handler:负责Message消息的发送与处理;
Message:消息载体,实现Parcelable接口;
MessageQueue:消息队列,对消息进行管理;
Looper:消息泵,不断的从MessageQueue消息队列中获取消息并派发到对应的Handler中进行处理;
Thread:线程,整个消息的调度是在这进行的。
二、实现过程
①创建消息
//创建一个消息实体
Message msg = Message.obtain(mHandler);
//对消息实体赋值
msg.what = 1;
//发送到对应的Handler(即在创建消息实体传入的mHandler)进行处理
msg.sendToTarget();
②消息传递过程
上面的sendToTarget会传递到Handler中
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
这里后面有调用到了
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;
}
这里我们注意到,他将我们这个消息加入到了MessageQueue中,并且这个message的target设置为this,目的是为了在处理消息环节,Message能找到正确的Handler
我们上面有说到消息是MessageQueue中的消息是通过Looper来传输到对应的 handler中处理的
while (true) {
Message msg = queue.next(); // might block
//中间省略了些代码
if (msg != null) {
//注意这里,我们将消息派发给刚才传入的this即外面的那个mHandler
msg.target.dispatchMessage(msg);
}
}
那我们就来看看Handler里面的dispatchMessage做了什么
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
这里如果没有Callback就直接调用handleMessage(msg)进行处理了(handleMessage在handler实现类中都有处理)
那这个Callback是做什么用的呢?我们知道消息传递有同步也有异步 或者定时,那这个Callback就是保持传入的Runnable用的
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
private final Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
这样呢 我们就能在收到消息的时候调用runnable了。
这样我们就明白了他们直接的关系了:
· Handler的处理过程运行在创建Handler的线程里
· 一个Looper对应一个MessageQueue
· 一个线程对应一个Looper
· 一个Looper可以对应多个Handler
· 不确定当前线程时,更新UI时尽量调用post方法
这里还有个问题我们需要注意:在主线程(UI线程)里,如果创建Handler时不传入Looper对象,那么将直接使用主线程(UI线程)的Looper对象(系统已经帮我们创建了);在其它线程里,如果创建Handler时不传入Looper对象,那么,这个Handler将不能接收处理消息。在这种情况下,通用的作法是:
class thread extends Thread
{
public Handler mHandler;
public void run()
{
Looper.prepare();
mHandler = new Handler() {
public void handlerMessage(Message msg) {
}
};
Looper.loop();
}
}
在创建Handler之前,为该线程准备好一个Looper(Looper.prepare),然后让这个Looper跑起来(Looper.loop),抽取Message,这样,Handler才能正常工作。
因此,Handler处理消息总是在创建Handler的线程里运行。而我们的消息处理中,不乏更新UI的操作,不正确的线程直接更新UI将引发异常。因此,需要时刻关心Handler在哪个线程里创建的。