今天在看Android源码的时候,看到了大量Handler的应用,和我以前开发APP的时候使用Handler的方法不太一样,所以花了一些时间来研究Handler。这里简单的记录一下。
Handler、Thread与Loop
一个线程(Thread)“可以”存在一个消息队列(MessageQueue)和一个消息循环(MessageQueue)。但是在线程创建的时候,这两个东西是不存在的。需要用Looper.prepare()来创建消息队列,用Looper.loop()来启动消息的循环。请看下面的这个例子。
public class LooperThread extends Thread {
public Handler mHandler;
public void run(){
Looper.prepare(); // 创建消息队列。
mHandler = new Handler(){
@Override
public void handlerMessage(Message msg){}
};
Looper.loop(); // 启动消息循环。这个要在run()函数的最后调用。
}
}
这个例子是在一个自定义的线程中创建了Looper并让消息队列循环跑起来。那么这样一个有Looper和MessageQueue的线程和Handler的关系是怎么样的呢?在Handler初始化的时候,如果使用的是无参的构造函数,那么它将获取当前线程的Looper和MessageQueue,如果初始化的时候传入了Looper,那么Handler将获取这个Looper以及对应的MessageQueue。换句话说,传入的是哪个线程的Looper,Handler就属于哪个线程。所以一个Handler只能属于一个Thread。
另外一句话就是一个线程却可以拥有多个Handler。这句话我在很多个地方都看到了,但是因为没有仔细的去分析源代码,所以没有找到这句话的来源,但是我可以给出一个例子,说明一个线程是可以拥有多个Handler的,在消息的传递过程中不会乱。例子如下:
// 发送消息一般有如下两种方法
Message msg = new Message();
msg.what = 1;
handler.sendMessage(msg);
Message msg = handler.obtainMessage();
msg.what = 1;
msg.sendToTarget();
很明显,第一种方法产生的msg将传递给调用sendMessage()方法的handler,第二种方法产生的msg将传递给调用obtainMessage()方法的handler。
说一句题外话,在Android APP开发中,因为更新UI只能在主线程中进行,所以经常会在主线程中定义Handler,子线程通过向Handler发送消息,由Handler对象的handleMessage()函数来更新UI。在这种情况下,并不需要显式地调用Looper.prepare()和Looper.loop()。这其中的原因就是在UI的ActivityThread中已经调用过了这两个函数,也就是说,每一个APP的主线程都默认定义好了Looper和MessageQueue,所以直接用就好了。有兴趣的朋友可以研究一下ActivityThread.java这个文件。
Handler的构造函数
Android源码中Handler的构造函数有好几个,分别如下:
public Handler() {
this(null, false);
}
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
/**
* @hide
*/
public Handler(boolean async) {
this(null, async);
}
/**
* @hide
*/
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();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
/**
* @hide
*/
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
我抽几个常用的简单分析一下。首先是默认构造函数:
public Handler() {
this(null, false);
}
可见它实际上将调用下面的构造函数:
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; // 获取当前线程的MessageQueue。
mCallback = callback;
mAsynchronous = async;
}
首先获取当前线程的Looper,然后通过这个Looper获取当前线程的MessageQueue。这样,线程的Looper和MessageQueue将交由Handler处理。
另外一个常用的构造函数如下:
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
它将调用的构造函数如下:
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
这里的Handler对象将绑定传入的Looper并通过传入的Looper对象获取其MessageQueue。
HandlerThread
HandlerThread是谷歌制造出来专为异步处理各种消息的线程,借助于它,我们可以非常方便的设计出异步处理程序。为什么方便?因为它默认的run()函数里已经构建好了Looper和MessageQueue。
public void run() {
mTid = Process.myTid();
Looper.prepare(); // 就是这里
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop(); // 还有这里
mTid = -1;
}
然后通过它的getLooper()方法即可获得这个线程的Looper。
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper; // 就是这里
}
然后绑定Handler与Looper就可以了。
下面,我给出一个典型的HandlerThread应用。
// 首先实例化一个MyHandlerThread。
MyHandlerThread mHandlerThread = new MyHandlerThread("Timothy");
// 让这个HandlerThread跑起来。
mHandlerThread.start();
// 获取HandlerThread的Looper,通过它将Handler与HandlerThread绑定起来。注意这里用的构造函数。
Handler mHandler = new Handler(mHandlerThread.getLooper(), mHandlerThread);
// 注意这里的MyHandlerThread实现了Callback接口。
private class MyHandlerThread extends HandlerThread implements Callback{
public MyHandlerThread(String name){
super(name);
}
@Override
public boolean handleMessage(Message msg){
return true;
}
}
这里要着重讲的是Handler为什么要选用上面的这个构造函数。这个构造函数的第一个参数好理解,就是将Handler与传进去的Looper绑定。那第二个参数呢?我们使用HandlerThread想要得到的效果是发送给Handler的消息将在线程中处理,即调用MyHandlerThread中的handleMessage()函数。我们可以看一下Handler类中的dispatchMessage()函数。这个函数就是分发Message的。
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();
}
这里首先检查msg是不是runable(为什么会是runable,后面解释)。这个分支在这里不会跑。那么就进入了else分支。首先检查mCallback是不是为空。这个查看我们是用的构造函数(就是介绍的第二个构造函数):
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
可见,mCallback就是构造函数的第二个参数。在我们的这个例子中,这个mCallback当然不是空,所以就会执行mCallback的handleMessage(),也就是我们MyHandlerThread的handleMessage()函数。我们的目的就达到了。
补充一句,如果mCallback为空,或者mCallback不为空,但是我们在MyHandlerThread的handleMessage()中返回的是false,就将调用这个handler对象的handleMessage()函数。后一种情况跟Android APP开发中的onKeyDown()函数的处理方法类似。
下面回过头来解释一下第一个if判断分支的作用。
我们知道,Handler除了传递Message这个作用外,还有另外一系列的方法,例如下面这几个:
public final boolean post(Runnable r);
public final boolean postDelayed(Runnable r, long delayMillis);
……
这几个函数的作用也是异步处理,不过传递的是Runable。当某些函数需要立即返回,但是这些函数的实际操作又要耗时时,就会调用这些函数,让耗时操作在未来的某个时间进行,同时立即返回。
我们这里跟踪一下post()函数的实现:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
// 这里创建了一个Message,并且把Runable对象存储在了它的callback属性里面。
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
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;
}
// 这里将创建的Message对象加入到MessageQueue里面。
return enqueueMessage(queue, msg, uptimeMillis);
}
post()函数的调用过程就是新建一个Message对象,将Runnable对象存储在这个Message对象的callback字段里面,然后将Message对象加入MessageQueue。所以当dispatch的时候,会检查当前Message的callback是不是为空,即是不是由Runable创建的,如果是Runnable对象,就运行之(handleCallback()函数)。