public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();// 获取到当前线程的looper
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;// 获取到looper管理的消息队列
mCallback = callback;// 自定义的回调函数
mAsynchronous = async;
}
其中有关内存泄露问题我们稍后再谈。先关注一下我们的handler在创建时做了哪些工作。在谈论整个通信机制的时候我们说过,一个线程只能有一个looper用来轮询唯一的一个消息队列,即线程,looper,消息的队列的关系是一一对应的。而handler和looper之间是一对多的关系,即一个looper可以由多个handler来为它服务。在handler的构造函数中,主要工作就是把handler和它要服务的looper,消息队列关联起来。
handler可以向队列中发送消息或者添加一个可执行的runnable对象,消息队列会安排在某一时刻进行消息处理或者执行runnable对象run方法:
•post(Runnable r):将runnable对象加入消息队列,该runnable对象将会被消息队列所在线程执行。
•postAtTime(Runnable, long): 将runnable对象加入消息队列,在指定的时间执行该runnable对象。
•postDelayed(Runnable r, long delayMillis):将runnable对象加入消息队列,经过指定延迟时间后执行。
•sendEmptyMessage(int what):将一条仅包含what值的消息发送给消息队列
•sendMessage(Message msg):将一条消息加入消息队列
•sendMessageAtTime(Message msg, long uptimeMillis):在指定时间将一条消息加入队列尾部
•sendMessageDelayed(Message msg, long delayMillis): 在经过指定时间延迟后,将一条消息加入队列尾部
通过这些方法,handler将message对象交给了消息队列messageQueue。looper从消息队列中取出message后,会调用message所持有的handlerdispatch方法,分发给handler来处理该消息:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {// 如果message对象持有回调对象,则执行它
handleCallback(msg);
} else {
if (mCallback != null) {// 如果当前handler持有消息处理的回调函数,则执行它
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);// 如果都没有,则执行用户自定义的消息处理方法
}
}
管家Looper和信箱MessageQueue
从上面的分析我们可以了解,message对象是通过handler间接的加入到消息队列中的,然后消息队列将message对象组织成一个队列提供给looper分发。如果只看名字,我们会猜想这个类中使用队列这种数据结构来组织message,然而并不是这样的。MessageQueue将message对象按时间顺序组织成一个链表的形式来管理。
在创建handler对象的时候,我们通过looper.myLooper方法从threadLocal中获取到与当前线程一一对应的looper对象。那么当前线程是何时创建了整个looper对象并将其放入threadLocal呢?在Android的UI线程中,早已自动替我们创建好了looper;而如果是我们自己创建的线程,那么就需要调用prepare方法来创建出looper对象:
public static void prepare() {
prepare(true);
}