HandlerThread源码分析

*注:阅读本文需要具备基本的Handler基础

一、常见问题

  1. HandlerThread是什么?

它是一个封装了Looper(Handler)机制的Thread。

  1. 它的应用场景是什么?

你可以将一些需要串行执行的子任务(耗时任务)交给它去做

二、简单使用

        val handlerThread = HandlerThread("thread1")
        handlerThread.start()
        val looper = handlerThread.looper
        var myHandler  = object : Handler(looper){
            override fun handleMessage(msg: Message) {
                //这里是运行在handlerThread这个线程
                Log.e("SSSS","handleMessage线程:"+Thread.currentThread().name)
                // 处理耗时任务
            }
        }

        myHandler.sendEmptyMessage(555)
        Log.e("SSSS","sendEmptyMessage线程:"+Thread.currentThread().name)

三、源码分析

//创建HandlerThread对象hou,必须先调用start()来初始化Looper对象,并执行loop(),
//Looper机制的使用都是这个流程(可参考ActivityThread中Looper的使用)
public class HandlerThread extends Thread {
    //设置优先级
    int mPriority;
    int mTid = -1;
    //属于此线程的Looper,间接持有了只属于此线程的MessageQueue对象
    Looper mLooper;
    private @Nullable Handler mHandler;

    // name:线程名
    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
    /**
     * Constructs a HandlerThread.
     * @param name 线程名
     * @param priority 优先级
     */
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    
    /**
     * 在loop()执行前,需要运行的代码可以放在这里
     */
    protected void onLooperPrepared() {
    }

    //调用start()后,run()开始执行
    @Override
    public void run() {
        mTid = Process.myTid();
        //初始化Looper、MessageQueue对象等
        Looper.prepare();
        //思考:这里加同步锁,是为了控制下面getLooper()中的同步代码块,同时只有一个地方能执行
        // 为了保证getLooper()中返回的mLooper对象一定是赋值过的
        synchronized (this) {
            //notifyAll(); 此方法也可以写在这里效果一致,调用notifyAll()并不是马上唤醒wait()处挂起的代码
            //而是整个同步块都执行完才会去唤醒        
            //用于对外暴露Looper对象     
            mLooper = Looper.myLooper();
            notifyAll(); //写在这里更符合人们的思维逻辑
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        //开启loop循环
        Looper.loop();
        mTid = -1;
    }
    
    /**
     * 
     * 
     * 
     * @return 返回 looper 对象
     */
    public Looper getLooper() {
        // 判断当前线程是否存活
        if (!isAlive()) {
            return null;
        }

        boolean wasInterrupted = false;

        // 如上面的使用案例中所示,此方法和 Thread.start()对应的run()不确定哪个先执行(因为在两个线程中),若run()
        // 先执行mLooper已被赋值不为null,直接返回皆大欢喜。
        // 如果是此方法先执行呢? mLooper=null,就需要调用wait(),挂起当前执行,释放对象锁,run()中的同步代码块就会
        // 得到此对象锁,给mLooper进行赋值,赋值后调用notifyAll(),继续执行wait()后面的代码返回mLooper对象。
        synchronized (this) {
            while (isAlive() && mLooper == null) {  //思考:为何用while 用if不行吗?
                try {
                    wait();
                } catch (InterruptedException e) {
                    wasInterrupted = true;
                }
            }
        }
        //对于要用while而不是if的原因可能是这样的,因为用户的行为是不可控的,假如用户也写了一个同步代码块:
        /*
         *    synchronized (this) { //也用了此HandlerThread作为对象锁
         *         notifyAll();  //在其他地方调用notifyAll(),而不是run()中调用,上面的wait()也有可能被恢复
                   // 此时mLooper = null,返回就会有问题,而使用while可以解决此问题,当wait()恢复后
                   // 依然去检查  mLooper是否为空,若不为空,跳出while循环返回;若为空继续调用wait()挂起
                   // 继续等待为 mLooper赋值           
         *         ...
         *    }   

        /*
         * We may need to restore the thread's interrupted flag, because it may
         * have been cleared above since we eat InterruptedExceptions
         */
        if (wasInterrupted) {
            Thread.currentThread().interrupt();
        }

        return mLooper;
    }

    /**
     * @return a shared {@link Handler} associated with this thread
     * @hide
     */
    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }

    /**
     * Quits the handler thread's looper.
     * <p>
     * Causes the handler thread's looper to terminate without processing any
     * more messages in the message queue.
     * </p><p>
     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
     * For example, the {@link Handler#sendMessage(Message)} method will return false.
     * </p><p class="note">
     * Using this method may be unsafe because some messages may not be delivered
     * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
     * that all pending work is completed in an orderly manner.
     * </p>
     *
     * @return True if the looper looper has been asked to quit or false if the
     * thread had not yet started running.
     *
     * @see #quitSafely
     */
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

    //安全退出looper循环
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    /**
     * Returns the identifier of this thread. See Process.myTid().
     */
    public int getThreadId() {
        return mTid;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值