前一篇文章中瞭解了AsyncTask
的使用和原理,這一篇輪到HandlerThread
這種異步任務的方式,HandlerThread
源碼中會涉及一些關於Handler
和Looper
的內容,不太瞭解的能夠先看一下這篇文章Android進階知識:Handler相關。java
HandlerThread
的使用有如下幾個步驟:android
1. 建立HandlerThread對象bash
HandlerThread handlerThread = new HandlerThread("myHandlerThread");
複製代碼
2.開啓HandlerThread異步
handlerThread.start();
複製代碼
3.建立HandlerThread的Handler,並複寫其handleMessage方法ide
Handler handler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case type1: {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d(TAG, Thread.currentThread().getName() + " type1 receive");
}
break;
case type2: {
for (percent = 0; percent <= 100; percent += 10) {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d(TAG, Thread.currentThread().getName() + " type2 " + percent + "% progress");
}
Log.d(TAG, Thread.currentThread().getName() + ":finish");
}
break;
}
}
};
複製代碼
4.經過Handler發送消息函數
Message message1 = Message.obtain();
message1.what = type1;
handler.sendMessage(message1);
Message message2 = Message.obtain();
message2.what = type2;
handler.sendMessage(message2);
複製代碼
5.使用完退出HandlerThreadoop
handlerThread.quit();
複製代碼
運行結果日誌:post
不管從HandlerThread
的名字仍是它的使用方法來看HandlerThread
都是一個線程Thread
加上一個Handler
的組合,其實也確實如此。先從它的構造方法開始看。ui
/**
* 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.
*/
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
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;
}
......
}
複製代碼
首先看到它確實是繼承了Thread
類,從HandlerThread
類上的註釋能夠看出HandlerThread
就是一個提供帶有Looper
的線程便利類,能夠經過這個Looper
建立Handler
。咱們知道子線程中使用Handler
須要本身手動建立Lopper
,而使用HandlerThread
就不須要了,它裏面已經幫咱們建立好了Looper
。HandlerThread
它有兩個重載的構造方法,構造方法中只作了兩件事,就是這個線程設置名字和優先級。做爲一個Thread
類想要使用它就必須調用start
方法開啓線程,開啓線程後就會執行它的run
方法,繼續來看它的run
方法實現。this
@Override
public void run() {
// 獲取線程id
mTid = Process.myTid();
// 建立Looper
Looper.prepare();
synchronized (this) {
// 獲取當前線程的Looper
mLooper = Looper.myLooper();
// 通知等待喚醒
notifyAll();
}
// 設置線程優先級
Process.setThreadPriority(mPriority);
// 開啓Looper循環前的準備方法
onLooperPrepared();
// 開啓輪詢
Looper.loop();
// 將線程id修改成-1
mTid = -1;
}
複製代碼
run
方法中首先獲取線程id
,而後就調用了Looper.prepare
方法建立一個Looper
,接着調用了Looper.myLooper
方法獲取到了當前線程的Looper
。接着經過notifyAll
通知等帶喚醒,這裏的等待是在HandlerThread
的getLooper
方法裏調用的wait
方法,getLooper
方法是爲了獲取該HandlerThread
中的Looper
。若是在沒調用HandlerThread
的start
方法開啓線程前就調用getLooper
方法就經過wait
方法暫時先進入等待,等到run
方法運行後再進行喚醒。喚醒以後run
方法中繼續設置了構造函數中傳入的優先級,接着調用了onLooperPrepared
方法,該方法是個空實現,該方法是爲了在Looper
開啓輪詢以前若是要進行某些設置,能夠複寫該方法。最後調用Looper.loop
開啓輪詢。
public Looper getLooper() {
// 若是該線程isAlive爲false直接返回null
if (!isAlive()) {
return null;
}
// 若是isAlive爲true但mLooper爲null,就進行等待直到mLooper被建立
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
複製代碼
onLooperPrepared
空實現。
protected void onLooperPrepared() {
}
複製代碼
HandlerThread
中還提供了兩個退出的方法分別對應Looper
中的兩個退出方法。
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
複製代碼
能夠看到無論哪一個方法其中都先獲取Looper
判斷不爲空後調用了Looper
中的對應的退出方法。使用完HandlerThread
後必定要記得調用退出方法中止Looper
,不然Looper
會一直輪詢。
除了以上方法,HandlerThread
裏還有一個getThreadHandler
獲取持有當前線程Looper
的Hanlder
,不過這個方法是hide
隱藏的。
/**
* @return a shared {@link Handler} associated with this thread
* @hide
*/
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
複製代碼
以上就是HandlerThread
全部源碼方法,能夠發現HandlerThread
源碼很少一共160多行,其實現的功能也不復雜,就是封裝了一個帶有Looper
的線程類,方便了咱們作異步耗時任務和通訊。不過使用仍是有幾個要注意的點:
HandlerThread
只有一個線程,因此在連續不停的使用Handler
的發送消息時,任務只能一個一個進行。HandlerThread
用完記得調用退出方法。Handler
因此會容易發生內存泄漏。