概要介紹
HandlerThread是一種特殊的Thread叶摄,也就是有Looper的thread狈究,既然有Looper的話碗淌,那我們就可以用此Looper來(lái)創(chuàng)建一個(gè)Handler,從而實(shí)現(xiàn)和它的交互抖锥。比如你可以通過(guò)與它關(guān)聯(lián)的Handler對(duì)象在UI線程中發(fā)消息給它處理亿眠。HandlerThread一般可以用來(lái)執(zhí)行某些background的操作,比如讀寫文件磅废、進(jìn)行一些計(jì)算(在此HandlerThread而非UI線程中)纳像。既然還是一個(gè)Thread系瓢,那么和一般的Thread一樣溶浴,也要通過(guò)調(diào)用其start()方法來(lái)啟動(dòng)它。它只是Android替我們封裝的一個(gè)Helper類,其源碼相當(dāng)簡(jiǎn)潔荆忍,有一些經(jīng)典的標(biāo)準(zhǔn)寫法禁灼,我們一起來(lái)看看昵仅。
源碼分析
和以往一樣退渗,我們先來(lái)看看其字段和構(gòu)造函數(shù):
int mPriority; // 線程優(yōu)先級(jí)
int mTid = -1; // 線程id
Looper mLooper; // 與此線程關(guān)聯(lián)的Looper
public HandlerThread(String name) { // 提供個(gè)名字,方便debug
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT; // 沒(méi)提供犀勒,則使用默認(rèn)優(yōu)先級(jí)
}
/**
* 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; // 使用用戶提供的優(yōu)先級(jí)屎飘,取Process.java中定義的常量
}
代碼很簡(jiǎn)單,相關(guān)的分析都直接寫在代碼的注釋里了贾费,值得注意的是這里的priority是基于Linux優(yōu)先級(jí)的钦购,而不是Java Thread類里的MIN_PRIORITY,NORM_PRIORITY铸本,MAX_PRIORITY之類肮雨,請(qǐng)注意區(qū)分(其實(shí)認(rèn)真閱讀方法的doc即可)遵堵。
接下來(lái)看看此類的3個(gè)關(guān)鍵方法:
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
// callback方法箱玷,如果你愿意可以O(shè)verride放自己的邏輯;其在looper開(kāi)始前執(zhí)行
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare(); // 此方法我們前面介紹過(guò)陌宿,會(huì)創(chuàng)建與線程關(guān)聯(lián)的Looper對(duì)象
synchronized (this) { // 進(jìn)入同步塊锡足,當(dāng)mLooper變的可用的使用,調(diào)用notifyAll通知其他可能block在當(dāng)前對(duì)象上的線程
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority); // 設(shè)置線程優(yōu)先級(jí)
onLooperPrepared(); // 調(diào)用回調(diào)函數(shù)
Looper.loop(); // 開(kāi)始loop
mTid = -1; // reset為invalid值
}
/**
* 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() {
if (!isAlive()) { // 如果線程不是在alive狀態(tài)則直接返回null壳坪,有可能是你忘記調(diào)start方法了舶得。。爽蝴。
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) { // 進(jìn)入同步塊沐批,當(dāng)條件不滿足時(shí)無(wú)限等待,
try { // 直到mLooper被設(shè)置成有效值了才退出while(當(dāng)然也可能是線程狀態(tài)不滿足)蝎亚;
wait(); // run方法里的notifyAll就是用來(lái)喚醒這里的
} catch (InterruptedException e) { // 忽略InterruptedException
}
}
}
return mLooper; // 最后返回mLooper九孩,此時(shí)可以保證是有效值了。
}
當(dāng)你new一個(gè)HandlerThread的對(duì)象時(shí)記得調(diào)用其start()方法发框,然后你可以接著調(diào)用其getLooper()方法來(lái)new一個(gè)Handler對(duì)象躺彬,最后你就可以利用此Handler對(duì)象來(lái)往HandlerThread發(fā)送消息來(lái)讓它為你干活了。
最后來(lái)看2個(gè)退出HandlerThread的方法梅惯,其實(shí)對(duì)應(yīng)的是Looper的2個(gè)退出方法:
/**
* 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(); // 注意這里是調(diào)用getLooper而不是直接使用mLooper宪拥,
if (looper != null) { // 因?yàn)閙Looper可能還沒(méi)初始化完成,而調(diào)用方法可以
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;
}
通過(guò)代碼我們可以看到其內(nèi)部都是delegate給了Looper對(duì)象她君,而Looper我們?cè)谇懊嬉步榻B過(guò)了,感興趣的同學(xué)可以翻看前面的分析或者查看這2個(gè)方法的doc葫哗,寫的都很詳細(xì)犁河。
至此這個(gè)簡(jiǎn)單的Handy class就算分析完畢了鳖枕。在實(shí)際的開(kāi)發(fā)中,如果你只是要做某些后臺(tái)的操作(短暫的桨螺,比如把某些設(shè)置文件load到內(nèi)存中)宾符,而不需要更新UI的話,那你可以優(yōu)先使用HandlerThread而不是AsyncTask灭翔。