HandlerThread 简介

简介

HandlerThread  继承自 Thread ,内部封装了 Looper 。调用 handlerThread.start() 方法之后,内部就会创建一个 Looper MessageQueue ,我们通过这个 Looper 对象来实例化一个 Handler ,然后我们就可以在其他线程中使用这个  Handler 了。
1.使用传统的 Thread + Handler 的方式实现线程间通信
我们需要自己去实现Looper对象,然后在Looper循环中创建Handler对象,从而接收Handler消息执行相应任务。
public Handler threadHandler;
new Thread(new Runnable() {
    @Override
    public void run() {
        Looper.prepare();
        threadHandler = new Handler(Looper.myLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                // 处理消息,因为这个方法是在子线程调用,所以要在这执行耗时任务
            }
        };
        Looper.loop();
    }
}).start();

2.使用HandlerThread的方式实现线程间通信

只需先创建一个 HandlerThread 实例,然后调用 handlerThread.start() 创建  Looper  对象,再通过 handlerThread.getLooper() 获取 HandlerThread  中的 Looper 对象,根据这个 Looper 对象,来创建我们的 Handler  ,来处理子线程中的业务逻辑。
HandlerThread handlerThread = new HandlerThread("handler-thread");
handlerThread.start(); // 必须在Handler创建前调用,因为线程start后才会创建Looper
Handler threadHandler = new Handler(handlerThread.getLooper()) {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        // 处理消息,在子线程调用,所以要在这执行耗时任务

    }
};

实现原理

public class HandlerThread extends Thread {
    int mPriority;  // 线程优先级
    int mTid = -1;  // 线程Id
    Looper mLooper; // Looper循环器对象
    private @Nullable Handler mHandler;  // Handler 对象

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    
    /**
     * 开启Looper循环之前的准备工作
     * 复写之后,添加自己的逻辑
     */
    protected void onLooperPrepared() {  }

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
    
    /**
     * 此方法返回与此线程关联的循环器。如果这个线程没有启动或者
     * 因为任何原因isAlive()返回false,这个方法将返回null。
     * 如果这个线程已经启动,这个方法将阻塞,直到循环器初始化为止。
     */
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        // 如果线程已经启动,则会等待,直到创建了循环器。
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

    /**
     * 返回一个已经与此线程进行关联的 Handler对象。
     */
    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }

    /**
     * 这是退出循环器Looper的方法,一旦调用了quit()方法,消息队列中的消息将会立即停止处理,
     * 并且之后发来的所有消息都会失败。比如sendMessage()方法会返回false。
     * 这是不安全的一种退出方式。即不管是否正在处理消息,直接移除所有回调。
     */
    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;
    }

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

HandlerThread中的优先级Priority

合理的分配 HandlerThread 线程的优先级,一定程度的优化线程。
它默认的优先级是: process.THREAD_PRIORITY_DEFAULT ,其值为 “0”
priority 的取值范围是 “-20 ~ 19”;数值越小,优先级越高。优先级越高的线程,获的的CPU资源越多,反之越少。但是作为工作线程的 HandlerThread 是没有必要设置这么高的优先级的,因而需要我们根据需求,来设置合理的优先级别。

HandlerThread的使用场景

由于它里面封装了 Looper  ,所以属于 Thread + Looper 的场景。子线程中执行耗时任务,多任务的操作。
适用于本地IO操作
可以使用HandlerThread来处理本地的IO读写的工作,因为本地IO操作大多数耗时都是毫秒级的,所以对于HandlerThread这种单线程 + 队列的形式,不会产生阻塞。我们也可以使用postAtFrontQueue() 方法来对本地IO读取操作,这样可以快速将读取操作加入到队列前面执行。比如:从数据库中读取数据显示到ListView列表中。
不适用于网络IO操作:
由于HandlerThread是单线程同步队列的,所以不适合处理网络IO的操作。  
HandlerThread优缺点
优点:只需开启一个线程,就可以执行多个任务。
缺点:虽然支持多任务,但是HandlerThread是同步的,不能实现并发。
           所以如果其中某一个线程 任务执行时间过长,就会导致后续的任务都会被延迟处理。
注意事项
HandlerThread 使用完成之后,需要调用其 quitSafe() 或者 quit() 方法来结束线程。
quitSafe() 会等待正在处理的消息处理完后再退出;
quit() 不管是否正在处理消息,都会直接移除所有回调。

猜你喜欢

转载自blog.csdn.net/m0_49508485/article/details/127255505