Android 中的 HandlerThread 类详解

Android 中的 HandlerThread 类详解

简介

HandlerThread 类继承至 Thread 类,你可以把它看做是一个普通的线程类;当然,既然我们今天要说它,就不能在把它看做是一个普通的线程类了类处理了。HandlerThread 类与普通的线程类的主要区别就是:重写 run() 方法,并且创建了一个属于自己线程包含消息队列 Looper 对象;同时提供了 getLooper() 方法给外界获取 Looper 对象。

好处

  1. 开发中如果多次使用类似 new Thread(){...}.start() 这种方式开启一个子线程,会创建多个匿名线程,难于管理且使得程序运行起来越来越慢,而 HandlerThread 自带 Looper 包含一个独立的队列使它可以通过消息来多次重复使用当前线程,节省开支;
  2. 既然 HandlerThread 自带包含队列的 Looper ,那么它就可以分担主线程的 Looper 队列的压力;
  3. Android系统提供的 Handler 类内部的 Looper 默认绑定的是UI线程的消息队列,对于非UI线程又想使用消息机制,那么 HandlerThread 内部的 Looper 是最合适的,它不会干扰或阻塞UI线程。

使用方式

private HandlerThread handlerThread; // HandlerThread 对象
private Handler workHandler; // 工作线程的Handler对象
private Handler uiHandler = new Handler() { // 主线程/UI线程 的Handler对象
    @Override
    public void handleMessage(Message msg) {
        Toast.makeText(MainActivity.this, "接收到刷新界面的消息: " + msg.what, Toast.LENGTH_SHORT).show();
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    handlerThread = new HandlerThread("handler_thread_test");
    handlerThread.start();
    // handlerThread.quit(); // 退出

    // 创建工作线程的Handler对象
    workHandler = new Handler(handlerThread.getLooper()) {
        @Override
        public void handleMessage(Message msg) {
            // 模拟耗时操作
            SystemClock.sleep(msg.arg1);
            Log.i("MainActivity", "Thread: " + Thread.currentThread().getName());
            // 发送刷新界面消息
            uiHandler.sendEmptyMessage(msg.what);
        }
    };

    Message message;
    for (int i = 1; i <= 3; i++) {
        message = Message.obtain();
        message.what = i;
        message.arg1 = 1000 * i;
        // 将 Message 对象发送到工作线程
        workHandler.sendMessage(message);
    }
}

源码解析

1.构造方法

// 指定线程名称
public HandlerThread(String name) {
    super(name);
    mPriority = Process.THREAD_PRIORITY_DEFAULT; // 优先级 0
}

// 指定线程名称和优先级 优先级:-19 ~ 19 ,19 表示优先级最低;默认 0
public HandlerThread(String name, int priority) {
    super(name);
    mPriority = priority;
}

2.初始化方法,按需重写

protected void onLooperPrepared() {
}

默认空实现,用于开启轮询前进行初始化。

3.getLooper() 方法

public Looper getLooper() {
    // 判断线程状态
    if (!isAlive()) {
        return null;
    }

    // If the thread has been started, wait until the looper has been created.
    // 如果线程已经启动,等待 Looper 创建完成
    synchronized (this) {
        while (isAlive() && mLooper == null) {
            // 如果线程是正在运行状态但是 mLooper 对象为 null,线程等待
            // 提前说明一下,是在 run() 方法中唤醒的
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
    }
    return mLooper;
}

4.run()方法

@Override
public void run() {
    mTid = Process.myTid();
    // 调用 Looper.prepare() 方法,将线程变为 Looper 线程
    Looper.prepare();
    synchronized (this) {
        // 获取当前线程的 Looper 对象
        mLooper = Looper.myLooper();
        // 唤醒线程,wait() 等待方法在 getLooper() 方法中调用
        notifyAll();
    }
    // 设置线程优先级
    Process.setThreadPriority(mPriority);
    // 回调初始化方法
    onLooperPrepared();
    // 启动轮询器,开始对消息队列进行轮询
    Looper.loop();
    mTid = -1;
}

5.结束方法

// 调用 looper.quit() 退出,清除全部消息(包括延时消息和非延时消息)
public boolean quit() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quit();
        return true;
    }
    return false;
}

// 调用 looper.quitSafely() 退出,清除所有的延时消息,把所有非延时消息进行发送
public boolean quitSafely() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quitSafely();
        return true;
    }
    return false;
}

6.其他方法

// 获取当前线程的 Handler 对象
public Handler getThreadHandler() {
    if (mHandler == null) {
        mHandler = new Handler(getLooper());
    }
    return mHandler;
}

// 获取当前线程 id
public int getThreadId() {
    return mTid;
}

HandlerThread 类源码非常简单,就是在普通的线程中创建了一个 Looper 对象使之变为了一个 Looper 线程。类的源码说明在注释上面已经非常清晰,就不在重复了。

总结

  • HandlerThreadLooper 转到子线程中处理,分担了 MainLooper 的工作量,降低了主线程的压力,使主界面更流畅;
  • 开启一个线程起到多个线程的作用。处理任务是串行执行,按消息发送顺序进行处理。HandlerThread 本质是一个线程,在线程内部,代码是串行处理的
  • 由于每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理;
  • HandlerThread 拥有自己的消息队列,它不会干扰或阻塞UI线程;
  • 对于网络操作,HandlerThread 并不适合,因为它只有一个线程,延时可能比较严重。

相关文章

《Android 中的 IntentService 类详解》
《AsyncTask 完全解析》
《Android中的Handler机制分析(一) Handler和Message分析》
《Android中的Handler机制分析(二) MessageQueue分析》
《Android中的Handler机制分析(三) Looper分析和Handler其他知识》

你可能感兴趣的:(Android,知识)