1. HandlerThread是什么
经常都会使用到HandlerThread,看了它源码以后发现,其实HandlerThread是Thread的子类,因此HandlerThread其实是一个线程,只不过其内部帮你实现了一个Looper的循环而已。
2. HandlerThread怎么用
HandlerThread的用法也是相当简单的。
- 创建实例对象
- 启动HandlerThread线程
- 构建循环消息处理机制
下面是示例代码:
HandlerThread handlerThread = new HandlerThread("demo_handler_thread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper()) {
@Override
public boolean handleMessage(Message msg) {
//实现自己的消息处理
return true;
}
};
也可以这样使用:
HandlerThread handlerThread = new HandlerThread("demo_handler_thread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
//实现自己的消息处理
return true;
}
});
3. HandlerThread的源码
打开HandlerThread的源码,你会发现它的源码真的很简单。首先是3个成员变量。
public class HandlerThread extends Thread {
int mPriority;// 线程优先级
int mTid = -1;// 线程id
Looper mLooper;// 与线程关联的Looper
public HandlerThread(String name) {// 提供个名字,方便debug
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;// 使用用户提供的优先级,基于linux优先级,取值在[-20,19]之间
}
...
}
注意
值得注意的是这里的priority是基于Linux的优先级的,而不是Java Thread类里的MIN_PRIORITY,NORM_PRIORITY,MAX_PRIORITY之类,请注意区分。
HandlerThrad的run方法
public class HandlerThread extends Thread {
...
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
@Override
public void run() {
//获得当前线程的id
mTid = Process.myTid();
//准备循环条件
Looper.prepare();
//持有锁机制来获得当前线程的Looper对象
synchronized (this) {
mLooper = Looper.myLooper();
//发出通知,当前线程已经创建mLooper对象成功,这里主要是通知getLooper方法中的wait
notifyAll();
}
//设置当前线程的优先级
Process.setThreadPriority(mPriority);
//该方法实现体是空的,子类可以实现该方法,作用就是在线程循环之前做一些准备工作,当然子类也可以不实现。
onLooperPrepared();
//启动loop
Looper.loop();
mTid = -1;
}
....
}
getLooper获得当前线程的Looper对象
public class HandlerThread extends Thread {
...
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason is isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
public Looper getLooper() {
//如果线程不是存活的,则直接返回null
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
//如果线程已经启动,但是Looper还未创建的话,就等待,知道Looper创建成功
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
该方法主要作用是获得当前HandlerThread线程中的mLooper对象。
首先判断当前线程是否存活,如果不是存活的,这直接返回null。其次如果当前线程存活的,在判断线程的成员变量mLooper是否为null,如果为null,说明当前线程已经创建成功,但是还没来得及创建Looper对象,因此,这里会调用wait方法去等待,当run方法中的notifyAll方法调用之后通知当前线程的wait方法等待结束,跳出循环,获得mLooper对象的值。
总结:在获得mLooper对象的时候存在一个同步的问题,只有当线程创建成功并且Looper对象也创建成功之后才能获得mLooper的值。这里等待方法wait和run方法中的notifyAll方法共同完成同步问题。
quit结束当前线程的循环
/**
* Quits the handler thread's looper.
* <p>
* Causes the handler thread's looper to terminate without processing any
* more messages in the message queue.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p class="note">
* Using this method may be unsafe because some messages may not be delivered
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
* that all pending work is completed in an orderly manner.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*
* @see #quitSafely
*/
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
/**
* Quits the handler thread's looper safely.
* <p>
* Causes the handler thread's looper to terminate as soon as all remaining messages
* in the message queue that are already due to be delivered have been handled.
* Pending delayed messages with due times in the future will not be delivered.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p>
* If the thread has not been started or has finished (that is if
* {@link #getLooper} returns null), then false is returned.
* Otherwise the looper is asked to quit and true is returned.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*/
//安全退出循环
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
/**
* Returns the identifier of this thread. See Process.myTid().
*/
public int getThreadId() {
return mTid;
}
}
分析:以上有两种让当前线程退出循环的方法,一种是安全的,一中是不安全的。至于两者有什么区别? quitSafely方法效率比quit方法标率低一点,但是安全。具体选择哪种就要看具体项目了。
总结
- HandlerThread适用于构建循环线程。
- 在创建Handler作为HandlerThread线程消息执行者的时候必须调用start方法之后,因为创建Handler需要的Looper参数是从HandlerThread类中获得,而Looper对象的赋值又是在HandlerThread的run方法中创建。