HandlerThread是一種特殊的Thread,也就是有Looper的thread,既然有looper的話,那我們就可以用此looper來
創建一個Handler,從而實現和它的交互,比如你可以通過與它關聯的Handler對象在UI線程中發消息給它處理。HandlerThread
一般可以用來執行某些background的操作,比如讀寫文件(在此HandlerThread而非UI線程中)。既然還是一個Thread,那麼
和一般的Thread一樣,也要通過調用其start()方法來啟動它。它只是Android替我們封裝的一個Helper類,其源碼相當簡潔,我們
下面來看看,很簡單。
和以往一樣,我們先來看看字段和ctor:
復制代碼
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之類,請注意區分(其實認真閱讀方法的doc即可)。
接下來看看此類的關鍵3個方法:
復制代碼
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() { // callback方法,如果你願意可以Override放自己的邏輯;其在loop開始前執行
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare(); // 此方法我們前面介紹過,會創建與線程關聯的Looper對象
synchronized (this) { // 進入同步塊,當mLooper變的可用的使用,調用notifyAll通知其他可能block在當前對象上的線程
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority); // 設置線程優先級
onLooperPrepared(); // 調用回調函數
Looper.loop(); // 開始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狀態則直接返回null,有可能是你忘記調start方法了。。。
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) { // 進入同步塊,當條件不滿足時無限等待,
try { // 直到mLooper被設置成有效值了才退出while(當然也可能是線程狀態不滿足);
wait(); // run方法裡的notifyAll就是用來喚醒這裡的
} catch (InterruptedException e) { // 忽略InterruptedException
}
}
}
return mLooper; // 最後返回mLooper,此時可以保證是有效值了。
}
復制代碼
當你new一個HandlerThread的對象時記得調用其start()方法,然後你可以接著調用其getLooper()方法來new一個Handler對象,
最後你就可以利用此Handler對象來往HandlerThread發送消息來讓它為你干活了。
最後來看2個退出HandlerThread的方法,其實對應的是Looper的2個退出方法:
復制代碼
/**
* 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(); // 注意這裡是調用getLooper而不是直接使用mLooper,
if (looper != null) { // 因為mLooper可能還沒初始化完成,而調用方法可以
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;
}
復制代碼
通過代碼我們可以看到其內部都是delegate給了Looper對象,而Looper我們在前面也介紹過了,感興趣的同學可以翻看前面的分析或者
查看這2個方法的doc,寫的都很詳細。
至此這個簡單的Handy class就算分析完畢了。在實際的開發中,如果你只是要做某些後台的操作(短暫的,比如把某些設置文件load
到內存中),而不需要更新UI的話,那你可以優先使用HandlerThread而不是AsyncTask。