作為一個Android開發(fā),Handler機制是一定要了解的。在我面試過程中,發(fā)現(xiàn)很多人對Handler和Looper機制非常了解,對答如流,但是卻不知道何為HandlerThread。本文我們就來簡單聊一下它
HandlerThread是Thread的子類,它的作用很明確,文檔說的也很清楚
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.
意思就是說HandlerThread幫我們創(chuàng)建好了Looper。
我們都知道,Android主線程的Looper是自動創(chuàng)建的,其他線程是沒有創(chuàng)建Looper的,需要我們自己創(chuàng)建。一般做法很簡單
@Override
public void run() {
Looper.prepare();
Looper.loop();
}
prepare()和loop()兩個方法不再贅述,我們先來看一個不用HandlerThread的例子:
Thread newThread = new Thread(new Runnable()
{
@Override
public void run() {
Looper.prepare();
Looper.loop();
}
});
newThread.start();
Handler handler = new Handler(newThread.getLooper());
相信不少人會用上面的方式創(chuàng)建一個異步線程的Handler,有沒有問題呢?肯定有。
newThread的looper是在這個線程運行之后創(chuàng)建的,所以,當執(zhí)行到Handler handler = new Handler(newThread.getLooper());的時候,newThread的looper可能還沒有創(chuàng)建好!
****這就是為什么我們需要HandlerThread,并不僅僅是因為它幫我們創(chuàng)建了一個looper,更重要的是它為我們處理了這個異步問題。****
來看下HandlerThread的實現(xiàn):
@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;
}
簡單的一個加鎖幫我們做了最重要的事情。
有人問我在
run()方法里面,mTid開始賦值Process.myTid(),為什么后來又復制-1了呢?仔細想一下就有答案了,因為Looper.loop()是個死循環(huán)啊,執(zhí)行到mTid = -1的時候,就是looper退出的時候。
插一句,這個mTid是干嘛的?
/** * Returns the identifier of this thread. See Process.myTid(). */
public int getThreadId() {
return mTid;
}
Thread里面是沒有getThreadId()方法的,Process.myTid()方法定義如下:
/** * Returns the identifier of the calling thread, which be used with * {@link #setThreadPriority(int, int)}. */
public static final int myTid() {
return Libcore.os.gettid();
}
原來tid是修改線程優(yōu)先級、調(diào)度策略時用來做線程唯一標識的。那么在HandleThread中,把mTid置為-1是幾個意思?筆者的理解是,HandlerThread本身是為looper服務的,looper終止以后,線程也會馬上終止,為防止開發(fā)者錯誤使用,所以將mTid置為-1。
關于HandlerThread另外一個容易忽略的問題就是退出Looper。Looper通過quit()和quitSafely()方法退出(記得,Looper.loop()之后是一個死循環(huán)),看看Looper的loop()方法的注釋
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */
public static void loop()
Looper使用完畢執(zhí)行quit本身就是一件容易忽略的事情,如果放到HandlerThread中,更是容易忘得一干二凈。所以HandlerThread為我們提供了兩個相同的方法:
public boolean quit(){}
public boolean quitSafely(){}
****不過說到底,維護Looper的生命周期還是我們每個開發(fā)者自己的事情,HandlerThread只不過是封裝了一下,幫我們處理一個異步問題罷了。****