当有人问你HandlerThread是什么时,请这样告诉他

HandlerThread是什么?

一个自带Handler的Thread?

字面意思上这么理解是没错,但是更确切的讲是一个内含有Looper的Thread,这点从HandlerThread的源码注释就可以得知。

/**
 * Handy class for starting a new thread that has a looper. The looper can then be 
 * used to create handler classes. Note that start() must still be called.
 */

用于启动具有looper的新线程的方便类。 可以使用looper来创建处理程序类。 注意仍然必须调用start()来启动。

要想获取一个与之绑定的Handler可以通过内置的getThreadHandler()方法获得。

public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }

那么,当从调用handlerThread.start()方法那一刻开始,其内部发生了什么呢?Thread的start()方法注释如下。

/**
 * Causes this thread to begin execution; the Java Virtual Machine
 * calls the <code>run</code> method of this thread.
 */

导致此线程开始执行; Java虚拟机调用此线程的<code> run </ code>方法。

So,去看看HandlerThread的run()方法。

@Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

run()方法里没有什么陌生的东西,先是调用了Looper.prepare()方法创建一个Looper,然后加了一个同步锁获取当前线程的Looper对象赋值到mLooper上并唤醒所有线程,再然后设置当前线程优先级,再然后调用了onLooperPrepared()方法,最后调用Looper.loop()开启循环。

可能会有些好奇为什么在赋值mLooper时要加同步锁,后面会有解释。

看到这里,你可能会想,这跟我们自己继承Thread在run方法里开启一个Looper没什么两样吗,的确,但是官方也说了HandlerThread是一个方便类,方便我们在子线程使用Handler。

对了,上面run()方法里的onLooperPrepared()方法是干什么的?

/**
 * Call back method that can be explicitly overridden if needed to execute some
 * setup before Looper loops.
 */
 protected void onLooperPrepared() {
 }

如果需要在Looper循环之前执行某些设置,可以复写此方法。

emmm,那run()方法里加同步锁是为什么呢?

如果你不想通过HandlerThread为我们提供的getThreadHandler()方法来获取一个Handler,HandlerThread也提供了getLooper()方法为你提供Looper对象创建实现自己的Handler。

public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

这下就明白为啥在run()方法同步锁里赋值mLooper完成后要在再唤醒所有线程了。因为此方法将阻塞线程,直到looper已初始化。

整个HandlerThread类也就不到200行代码,除了上面那些,它还封装了线程不使用时退出Looper的方法。

public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

可以看出,HandlerThread真的是一个方便类啊,cao方便啊!

HandlerThread的使用场景

相比于普通的Thread,我为什么要使用HandlerThread?

对于普通的Thread,执行一遍就结束了,一个实例不能start多次,如果你不止一次启动同一个示例,那么将会抛出一个IllegalThreadStateException异常,这些在Thread的源码里都有注释写到。

/**
 * It is never legal to start a thread more than once.
 * 不止一次启动线程永远不合法
 * In particular, a thread may not be restarted once it has completed execution.
 * 特别是,一旦完成执行,线程可能无法重新启动。
 * @exception  IllegalThreadStateException  if the thread was already started.         
 *             如果线程已经启动将抛出IllegalThreadStateException异常
 */

如果我要频繁的操作数据库、大文件、请求网络,我就要频繁的创建Thread示例调用start(),又或是需要执行一系列串行操作;而HandlerThread由于自带Handler,也就相当自带了一个任务队列,需要进行耗时操作的时候只要通过Handler执行send或post系列操作就行,不再需要频繁创建Thread,节省资源。

发布了45 篇原创文章 · 获赞 18 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Ever69/article/details/96863059