HandlerThread详解

概述

在日常开发中,我们经常会通过 new Thread(){}.start(); 的方式来开辟一个新的线程。但是如果我们想要多次执行任务的时候,通过这种方式我就会创建多个线程,这样会使我们的程序运行起来越来越慢。通常情况下我会采用 HandlerThread 的方式来开辟一个线程,那么 HandlerThread 是什么呢?今天我们来介绍一下 HandlerThread。

正文

HandlerThread 是 Thread 的一个子类,HandlerThread 自带 Looper 使他可以通过消息队列来重复使用当前线程,节省系统资源开销。这是它的优点也是缺点,每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。它的使用也比较简单。

HandlerThread thread = new HandlerThread("MyHandlerThread");
thread.start();

mHandler = new Handler(thread.getLooper());
mHandler.post(new Runnable(){
    //...
});

接下来我们写一个完整的 Demo,然后在分析一下它的实现原理。

public class MainActivity extends AppCompatActivity {

    private HandlerThread handlerThread;
    private Handler handler;
    private Button button;
    private int k = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button = (Button) findViewById(R.id.button);

        handlerThread = new HandlerThread("suibian");
        handlerThread.start();
        handler = new Handler(handlerThread.getLooper());


        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                handler.post(runnable);
            }
        });
    }

    private Runnable runnable = new Runnable() {
        @Override
        public void run() {

            for (int i = 0; i < 5; i++){
                try {
                    Thread.sleep(1000);
                    Log.d("test","第" + k + "个任务--》" + i + "");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            k++;
        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        handlerThread.quit();
    }
}

我们连续点击两次 Button,让它执行两次任务,我们来看一下它的 Log 信息。

我们发现它不会立即去执行第二次任务,而是等待第一次任务结束之后再去执行第二次任务,我们来看一下它的原理。

源码分析

我们来看一下 HandlerThread 的源码:

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
            ...
            
    /**
     * Call back method that can be explicitly overridden if needed to execute some
     * setup before Looper loops.
     */
    protected void onLooperPrepared() {
    }

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

    .....

}

它的代码比较短,我们主要来看一下它的 run() 方法,我们发现它和普通 Thread 不同之处在于它在 run() 方法内创建了一个消息队列(如果不太了解消息机制的同学可以看一下 Android 中的消息机制来了解一下),然后来通过 Handler 的消息的方式来通知 HandlerThread 执行下一个具体的任务。由于 HandlerThread 的 run() 方法内 Looper 是个无限循环,所以当我们不需要使用 HandlerThread 的时候可以通过 quit() 的方法来终止。

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

quit() 实际上就是让 run() 内的 Looper 停止循环。

整体流程

当我们使用 HandlerThread 创建一个线程,它 statr() 之后会在它的线程创建一个 Looper 对象且初始化了一个 MessageQueue(消息队列),通过 Looper 对象在他的线程构建一个 Handler 对象,然后我们通过 Handler 发送消息的形式将任务发送到 MessageQueue 中,因为 Looper 是顺序处理消息的,所以当有多个任务存在时就会顺序的排队执行。当我们不使用的时候我们应该调用它的 quit() 或者 quitSafely() 来终止它的循环。

本文转载自:https://www.jianshu.com/p/5b6c71a7e8d7