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;
}
- 构造函数(String name)只需要传入线程的名称,就会为你创建对应名为name的自线程,其权重为0。
- 构造函数(String name, int priority)这需要创建者输入线程名字和权重,其实和👆的构造方法区别不大。
注意:权重越高,线程优先级越高,越容易被执行(相对而言)。
子线程如何创建
- 构造方法里面调用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的创建
- 内部会在你需要使用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方法
- getLooper方法内部是判断当前HandlerThread的mLooper变量是否被初始化了,如果没有就调用wait进行挂起。如果挂起了什么时候唤醒了?
- 唤醒是在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了。
总结
- 如果你需要发送某些特殊事件回到子线程去处理,我建议直接使用HandlerThread。不大建议使用传统的自定义Thread里面在new Handler,毕竟google官网都已经封装好了,为啥不用呢?(来自一名懒惰程序员的呐喊)
-
用传统方式很容易遗忘了new Handler要在Looper.pepare之后执行,要不然会抛出异常。
image.png
网友评论