Android HandlerThread解析

477 阅读2分钟

一、HandlerThread是什么

HandlerThread(public class HandlerThread extends Thread{})是一个自带Looper的线程,Looper可以用于创建Handler对象。

二、HandlerThread的作用

如下代码所示,在Handler的构造方法中,通过Looper.myLooper()方法,获取当前线程中的Looper对象,如果获取到的Looper对象为null,系统会给我抛出一个Can't create handler inside thread that has not called Looper.prepare()的运行时异常;

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;
    }
为什么在主线程中我们可以直接创建Handler对象呢

我们可以查看ActivityThread类,在main()方法中执行了 Looper.prepareMainLooper()方法,在prepareMainLooper()方法中,系统为主线程创建了Looper对象,所以在主线程才不会抛出Looper为null不能创建Handler的运行时异常;
如果我们需要使用Handler给子线程发送消息,就需要自己创建Handler,Looper,并调用Looper.loop()方法。HandlerThread正是为这样的使用场景所设计的,把使用细节封装了起来,简化了我们的使用流程。

三、如何使用HandlerThread

HandlerThread handlerThread = new HandlerThread("handler-thread-test");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper()) {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        Log.i("tag", "当前线程名字=" + Thread.currentThread().getName());
        //接收来自主线程的消息
        if (msg != null && msg.obj != null && msg.obj instanceof String) {
            String str = (String) msg.obj;
            Log.i("tag", "str:" + str);
            try {
                //耗时操作
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
   }
};

//主线程给工作线程发送消息
Message message = handler.obtainMessage();
message.obj = "这是一条来自主线程的消息";
handler.sendMessage(message);

执行结果: 注:需要先调用start方法,才能创建Handler。由下代码可见,Looper对象是在run方法中创建的,所以如果不启动线程,获取的Looper对象还是为null;handler.post run方法是在子线程中,因此可以执行一些耗时操作;

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

当我们启动了HandlerThread,如果还没有执行run()方法,此时获取Looper对象的方法getLooper()就会一直处于等待状态,直到执行了run方法后,才会唤醒getLooper()方法,并返回Looper对象。同时,如果没有启动线程的话,获取Looper对象,则直接返回null。代码如下:

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,可以调用quit()或quitSafely()结束线程执行。
由于个人能力和水平有限,如有不足之处,希望大家能够给与批评和指正,希望能和大家一起学习,一起进步。