Android多线程之HandlerThread详解

一 HandlerThread介绍

当系统中有多个耗时任务需要执行时,每个任务都会开启一个新线程去执行耗时任务,这样会导致系统多次创建和销毁线程,从而影响性能。为了解决这一问题,Android 提供了 HandlerThread,HandlerThread 是在线程中创建一个 Looper 循环器,让 Looper 轮询消息队列,当有耗时任务进入队列时,则不需要开启新线程,在原有的线程中执行耗时任务即可,否则线程阻塞。

二 工作原理

  • HandlerThread 继承 Thread,在 Thread 开始执行时跟主线程在 ActivityThread.main() 方法内执行代码逻辑类似,初始化 Looper–Looper.prepare(),轮询消息–Looper.loop()
  • 初始化 Handler 时,使用 HandlerThread 线程的 Looper 对象初始化---- new Handler(Looper) 构造方法
  • 至于为什么是在子线程内执行是因为此 Handler 使用的 Looper 是子线程创建的,执行 message.target.dispatchMessage() 也在子线程内,所以最终执行的 Runnable 或者 handleMessage() 也会在子线程内。

三 实例代码

  // 步骤1:创建HandlerThread实例对象
  // 传入参数 = 线程名字,作用 = 标记该线程
  HandlerThread mHandlerThread = new HandlerThread("handlerThread");
  // 步骤2:启动线程
  mHandlerThread.start();
  // 步骤3:创建工作线程Handler & 复写handleMessage()
  // 作用:关联HandlerThread的Looper对象、实现消息处理操作 & 与 其他线程进行通信
  // 注:消息处理操作(HandlerMessage())的执行线程 = mHandlerThread所创建的工作线程中执行
  Handler workHandler = new Handler( handlerThread.getLooper() ) {
            @Override
            public boolean handleMessage(Message msg) {
                ...//消息处理
                return true;
            }
        });

  // 步骤4:使用工作线程Handler向工作线程的消息队列发送消息
  // 在工作线程中,当消息循环时取出对应消息 & 在工作线程执行相关操作
  // a. 定义要发送的消息
  Message msg = Message.obtain();
  //消息的标识
  msg.what = 1;
  // b. 通过Handler发送消息到其绑定的消息队列
  workHandler.sendMessage(msg);

// 步骤5:结束线程,即停止线程的消息循环
  mHandlerThread.quit();

四 源码分析

4.1 实例化HandlerThread

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    //当前线程持有的Looper对象
    Looper mLooper;
    private @Nullable Handler mHandler;
    // 方式1. 默认优先级
    public HandlerThread(String name) {
        // 通过调用父类默认的方法创建线程
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    // 方法2. 自定义设置优先级
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    ......
}

4.2 启动HandlerThread

    @Override
    public void run() {
        // 1. 获得当前线程的id
        mTid = Process.myTid();
        // 2. 创建1个Looper对象 & MessageQueue对象
        Looper.prepare();
        // 3. 通过持有锁机制来获得当前线程的Looper对象
        synchronized (this) {
            mLooper = Looper.myLooper();
            // 发出通知:当前线程已经创建mLooper对象成功
            // 此处主要是通知getLooper()中的wait()
            notifyAll();
        }
        // 4. 设置当前线程的优先级
        Process.setThreadPriority(mPriority);
        // 5. 在线程循环前做一些准备工作
        // 该方法实现体是空的,由子类决定是否实现
        onLooperPrepared();
        // 6. 进行消息循环,即不断从MessageQueue中取消息 & 派发消息
        Looper.loop();
        mTid = -1;
    }

run() 内所做操作和 ActivityThread.main() 方法内所操作的东西大体相类似。不同的是,利用了锁机制来保证 getLooper() 获取 looper 正确。

4.3 获取实例化Handler要用到的Looper

    public Looper getLooper() {
        // 若线程不是存活的,则直接返回null
        if (!isAlive()) {
            return null;
        } 
        // 若当前线程存活,再判断线程的成员变量mLooper是否为null
        // 直到线程创建完Looper对象后才能获得Looper对象,若Looper对象未创建成功,则阻塞
        synchronized (this) {      
            while (isAlive() && mLooper == null) {
                try {
                    // 此处会调用wait方法去等待
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        // 上述步骤run()使用 持有锁机制 + notifyAll()  获得Looper对象后
        // 则通知当前线程的wait()结束等待 & 跳出循环
        // 最终getLooper()返回的是在run()中创建的mLooper对象
        return mLooper;
    }
  • 在获得 HandlerThread 工作线程的 Looper 对象时存在一个同步的问题:只有当线程创建成功 & 其对应的 Looper 对象也创建成功后才能获得 Looper 的值,才能将创建的 Handler 与 工作线程的 Looper 对象绑定,从而将 Handler 绑定工作线程
  • 解决方案:即保证同步的解决方案 = 同步锁、wait() 和 notifyAll(),即 在 run() 中成功创建 Looper 对象后,立即调用 notifyAll()通知 getLooper() 中的 wait()结束等待 & 返回 run() 中成功创建的 Looper 对象,使得 Handler 与该 Looper 对象绑定

五 总结

  • HandlerThread 本质上是一个线程类,它继承了 Thread
  • HandlerThread 有自己的内部 Looper 对象,可以进行 looper 循环
  • 通过获取 HandlerThread 的 looper 对象传递给 Handler 对象,可以在 handleMessage 方法中执行异步任务
  • 创建 HandlerThread 后必须先调用 HandlerThread.start() 方法,Thread 会先调用 run 方法,创建 Looper 对象
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值