Handler(八)--HandlerThread

系列目录: Handler机制原理

1. HandlerThread介绍

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

2. 工作原理

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

3. 使用实例代码

  // 步骤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. 源码分析

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;
    }
    ...
}

HandlerThread类继承自Thread类

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;
    }
  1. 在获得HandlerThread工作线程的Looper对象时存在一个同步的问题:只有当线程创建成功 & 其对应的Looper对象也创建成功后才能获得Looper的值,才能将创建的Handler 与 工作线程的Looper对象绑定,从而将Handler绑定工作线程
  2. 解决方案:即保证同步的解决方案 = 同步锁、wait() 和 notifyAll(),即 在run()中成功创建Looper对象后,立即调用notifyAll()通知 getLooper()中的wait()结束等待 & 返回run()中成功创建的Looper对象,使得Handler与该Looper对象绑定。

主要功能代码既是如此,HandlerThread内的其他源码不再做额外分析

你可能感兴趣的:(Handler(八)--HandlerThread)