HandlerThread类的使用和分析

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/ruancoder/article/details/52452397
概述
HandlerThread继承自Thread类,本质上还是Thread。与普通Thread的区别在于,它在创建一个线程的同时也创建了一个绑定该线程的消息循环,可以在当前线程中分发和处理消息。

Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.

官方文档:
https://developer.android.com/reference/android/os/HandlerThread.html

使用
通过下面四步我们可以创建HandlerThread。
// 1.创建HandlerThread对象,并为子线程指定一个名称
HandlerThread handlerThread = new HandlerThread("ruancoder");
// 2.调用start()。此时内部run()方法执行,会创建一个绑定当前线程的Looper对象
handlerThread.start();
// 3.获取HandlerThread的Looper
Looper looper = handlerThread.getLooper();
// 4.使用上面的Looper创建Handler
Handler handler = new Handler(looper);

创建完成之后就可以开始使用了,调用handler的post()方法,Runnable的run()方法将在子线程中执行。
handler.post(new Runnable() {
    @Override
    public void run() {
        // sub thread
    }
});

同样也可以使用Handler发消息的方式。可以在Handler创建时,重写handleMessage()方法。
Handler handler = new Handler(looper) {
    @Override
    public void handleMessage(Message msg) {
        // sub thread
    }
};
然后调用sendMessage()或sendEmptyMessage(),handleMessage()方法将会在子线程中执行。
// 1
handler.sendEmptyMessage(MSG);
// 2
handler.sendMessage(msg);

如果想让HandlerThread退出,可以调用HandlerThread的quit()或quitSafely()。

分析

在介绍HandlerThread之前,先来看一下如果我们需要在子线程中创建Handler该如何实现。

package net.csdn.blog.ruancoder;

public class MainActivity extends Activity {
    private Handler mHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        new Thread(new Runnable() {
            @Override
            public void run() {
	        ......

                Looper.prepare();// 1
                mHandler = new Handler(Looper.myLooper());// 2
                Looper.loop();// 3
            }
        }).start();
    }
}

在子线程的run()方法中,分三步来执行。
1.使用Looper.prepare()创建绑定当前线程的Looper对象;
2.使用上面的Looper对象创建Handler对象;
3.使用Looper.loop()开启消息循环。

关于Message、MessageQueue、Handler、Looper的执行流程,可参考如下链接:
http://blog.csdn.net/ruancoder/article/details/52081614

在HandlerThread类的源码中,采用了同样的方式来创建Looper对象,并赋值给成员变量mLooper。
public class HandlerThread extends Thread {
    Looper mLooper;

    ......

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

    ......
}

getLooper()方法返回上面创建的mLooper对象。我们通过调用getLooper()方法,可以获取到mLooper对象去创建Handler。
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;
}

HandlerThread也可以控制线程的优先级。在HandlerThread类中,有一个成员变量mPriority,该变量在run()方法中通过调用Process.setThreadPriority(mPriority)被使用到。mPriority默认值为THREAD_PRIORITY_DEFAULT,我们也可以在构造方法中传入参数去修改。
注意,mPriority的取值只限于android.os.Process类中的常量,不能取自java.lang.Thread。
int mPriority;

public HandlerThread(String name) {
    super(name);
    mPriority = Process.THREAD_PRIORITY_DEFAULT;
}

public HandlerThread(String name, int priority) {
    super(name);
    mPriority = priority;
}

如果需要退出消息循环,可以调用quit()或quitSafely()方法。可以看到,方法内部执行的是成员变量mLooper的quit()和quitSafely()方法。在Looper类中,又执行的是MessageQueue的quit(boolean safe)方法。当调用quit()方法时,MessageQueue消息池中所有的消息全部被清空,包括延迟消息和非延迟消息。而调用quitSafely()方法时,只会清空MessageQueue消息池中所有的延迟消息,并将消息池中所有的非延迟消息派发出去让Handler处理。
public boolean quit() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quit();
        return true;
    }
    return false;
}

public boolean quitSafely() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quitSafely();
        return true;
    }
    return false;
}

优点
为什么要使用HandlerThread呢?

1.开发中如果多次使用类似new Thread(){}.start()这种方式开启子线程,会创建多个匿名线程,使得程序运行起来越来越慢,而HandlerThread自带Looper使他可以通过消息机制来多次重复使用当前线程,节省开支。
2.Handler类内部的Looper默认绑定的是UI线程的消息队列,对于非UI线程如果需要使用消息机制,自己去创建Looper较繁琐,由于HandlerThread内部已经自动创建了Looper,直接使用HandlerThread更方便。

阅读更多
换一批

没有更多推荐了,返回首页