HandlerThread的使用及原理浅析

对HandlerThread的一些总结。

概述

HandlerThread提供了一种能在子线程进行异步操作的消息处理机制,本质上它封装ThreadLooper来在子线程进行消息的存储和分发。
涉及到Handler的相关知识Handler 原理知识点回顾

使用

简单的例子:

HandlerThread handlerThread = new HandlerThread("handlerThread"){
            @Override
            protected void onLooperPrepared() {
                super.onLooperPrepared();
                Log.d("执行","准备工作");
            }
        };
        handlerThread.start();
        //必须在调用handlerThread.start()之后才能创建Handler
        final Handler handler = new Handler(handlerThread.getLooper()){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Log.d("消息","在 "+Thread.currentThread().getName()+" 线程,收到 "+msg.obj);
            }
        };
        handler.sendMessage(Message.obtain(handler,1,"test1"));

控制台输出:

08-02 13:57:43.023 27006-27026/com.franky.test D/执行: 准备工作
08-02 13:57:43.023 27006-27026/com.franky.test D/消息: 在 handlerThread 线程,收到 test1

在合适的地方调用退出操作:

        handlerThread.quit();
        //handlerThread.quitSafely(); API 18才支持此方法

使用相对比较简单,总结如下:

  • 创建HandlerThread对象,可以重写onLooperPrepared()方法做一些初始化操作;
  • 调用handlerThread.start()方法;
  • 创建Handler,在构造中传入handlerThread.getLooper()方法创建的Looper对象,重写handleMessage(Message msg)方法,在子线程处理消息;
  • 使用Handler对象在相关场景发送处理消息;
  • 适时退出异步操作

    原理

    本身HandlerThread的源码比较少,直接贴出:

 //本身继承了Thread类
 public class HandlerThread extends Thread {
    int mPriority;//线程优先级
    int mTid = -1;//线程id
    Looper mLooper;//Looper对象
    private @Nullable Handler mHandler;//无法调用

//name为线程的名字
    public HandlerThread(String name) {
        super(name);
        //线程的优先级,这是默认级别,其他的级别在Process中有存储
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

    //可以传入优先级的构造,优先级来自android.os.Process类中
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }

    //可以重写此方法做准备工作
    protected void onLooperPrepared() {
    }
    //在调用HandlerThread.start()方法后,run方法会运行
    //这里主要是进行了Looper对象的创建和初始化
    @Override
    public void run() {
        mTid = Process.myTid();//获取线程id
        Looper.prepare();//准备当前线程的Looper,使用了ThreadLocal存储
        synchronized (this) {//进入同步代码块
            mLooper = Looper.myLooper();//获取当前线程Looper
            notifyAll();//通知线程
        }
        Process.setThreadPriority(mPriority);//设置线程优先级
        onLooperPrepared();//调用准备方法
        Looper.loop();//开启消息循环
        mTid = -1;//重置线程ID
    }

//主要用于获取当前线程关联的Looper对象,用于创建Handler使用
    public Looper getLooper() {
    //如果线程没有存活,直接返回Null
        if (!isAlive()) {
            return null;
        }

    //进入同步代码
        synchronized (this) {
        //如果线程存活,但是Looper对象还没初始化成功的时候,wait,等待Looper初始化完毕后唤醒
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

    //此方法标记为@hide,外部无法直接调用
    /**
     * @return a shared {@link Handler} associated with this thread
     * @hide
     */
    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }

   //调用该方法,Looper对象中的MessageQueue存储的Messag,将全部被情况
   //无论是不是延迟消息都将被移除,如果想要保障非延迟消息执行的话,那么使用quitSafely()方法
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

    //和quit()方法的区别就是只有延迟方法才会被移除,当前的消息会被处理完成 API18支持
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    //获取线程Id
    public int getThreadId() {
        return mTid;
    }
}

其实整个HandlerThread做的工作就是在Thread中封装了Looper对象,以此在创建的Handler中能够进行异步的消息处理。

总结

如果有耗时操作可以考虑使用HandlerThread机制。
创建HandlerThread后必须首先调用start方法,以此来准备子线程需要的Looper对象,之后再创建Handler对象时,才能在构造方法中调用new Handler(handlerThread.getLooper())来使用Looper对象,注意创建的先后顺序。

参考文章:
Android中Looper的quit方法和quitSafely方法

猜你喜欢

转载自blog.csdn.net/franky814/article/details/81387000