美文网首页
HandlerThread源码解析与使用

HandlerThread源码解析与使用

作者: Magic旭 | 来源:发表于2019-06-04 14:23 被阅读0次

HandlerThread类的用法

前传:如果你还沉醉在于创建普通自线程,沉迷于创建线程通信的Handler,不如来试试HandlerThread类的使用。其内部的源码也非常简单,只要你稍微看过Handler,Thread,Looper内部的实现流程就能把HandlerThread类的源码看懂了。

HandlerThread构造函数
public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
    /**
     * Constructs a HandlerThread.
     * @param name
     * @param priority The priority to run the thread at. The value supplied must be from 
     * {@link android.os.Process} and not from java.lang.Thread.
     */
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
  1. 构造函数(String name)只需要传入线程的名称,就会为你创建对应名为name的自线程,其权重为0。
  2. 构造函数(String name, int priority)这需要创建者输入线程名字和权重,其实和👆的构造方法区别不大。
    注意:权重越高,线程优先级越高,越容易被执行(相对而言)。
子线程如何创建
  1. 构造方法里面调用Thread类的super(name)方法,内部实现和我们平时构建子线程没啥区别,区别在于调用了不同的构造方法,曾经年少的我们是啥都不传的,所以Thread.name = "Thread-" + nextThreadNum();现在的我们成长了,需要给它们定义一个感(中)人(二)的名字了。两者对应的构造函数可以看下面的源码。
 /**
     * Allocates a new {@code Thread} object. This constructor has the same
     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
     * {@code (null, null, gname)}, where {@code gname} is a newly generated
     * name. Automatically generated names are of the form
     * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
     */
    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }

/**
     * Allocates a new {@code Thread} object. This constructor has the same
     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
     * {@code (null, null, name)}.
     *
     * @param   name
     *          the name of the new thread
     */
    public Thread(String name) {
        init(null, null, name, 0);
    }
Handler的创建
  1. 内部会在你需要使用Handler在子线程通信的时候生成实例,可以看到Handler的构造函数中传入了当前子线程的Looper;平时我们在子线程生成Handler是不在构造函数中传递任何参数的,但其实Handler内部也通过Looper.myLooper来获取当前线程的looper,具体源码如下。
//不传任何构造参数的Handler生成方法
public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }
        //这里获取Handler所在线程的Looper
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

//HandlerThread返回Handler的方法
/**
     * @return a shared {@link Handler} associated with this thread
     * @hide
     */
    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }
getLooper方法
  1. getLooper方法内部是判断当前HandlerThread的mLooper变量是否被初始化了,如果没有就调用wait进行挂起。如果挂起了什么时候唤醒了?
  2. 唤醒是在run方法里面,首先会执行Looper.peapare方法,储存 ThreadLocalMap 里面,key是当前线程,value是looper实例。
@Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

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

注意:可以看出,其内部还是通过Looper.prepare()方法创建Handler的实例,只不过高度封装起来,对开发者来说是透明化的。开发者不需要再到自己的Thread里面生成Handler了。

总结

  1. 如果你需要发送某些特殊事件回到子线程去处理,我建议直接使用HandlerThread。不大建议使用传统的自定义Thread里面在new Handler,毕竟google官网都已经封装好了,为啥不用呢?(来自一名懒惰程序员的呐喊)
  2. 用传统方式很容易遗忘了new Handler要在Looper.pepare之后执行,要不然会抛出异常。


    image.png

相关文章

网友评论

      本文标题:HandlerThread源码解析与使用

      本文链接:https://www.haomeiwen.com/subject/cxllxctx.html