Thread、Handler与HandlerThread

来源:互联网 发布:论文meta分析数据 编辑:程序博客网 时间:2024/04/27 04:21

今天在看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()函数)。

2 0