前言
在讀這篇文章之前最好先讀一下我之前寫的關於Handler原理的文章:Android Handler消息源碼分析,這樣會比較容易理解handlerThread的原理。
內容
HandlerThread相信很多人都已經用過,還不瞭解或者沒有用過的同學請自行搜索。
先貼一下sample code
HandlerThread handlerThread = new HandlerThread("sample");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.v("test","handleMessage");
return false;
}
});
for(int i=0;i<10;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.sendMessage(Message.obtain());
}
廢話不多講,直接看HandlerThread的構造方法
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
因爲HandlerThread類是繼承自Thread類,所以先調用父類的方法,將Thread Name賦值,接着設置線程優先級。
接着在sample code中會調用start()
方法,我們知道這個會讓線程開始運行,並調用run()
方法,所以我們直接看run()
方法。
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
主要工作內容就是調用Looper.prepare()
,初始化Looper對象,並給mLooper
賦值。我們知道Looper.prepare()
方法在哪個線程調用,這個Looper就屬於哪個線程,所以在這裏這個Looper就屬於HandlerThread這個子線程。接着加一個鎖,給mLooper
賦值,然後通知等待線程。這段代碼是對應於後面的另一個getLooper()
方法,然後調用onLooperPrepared()
,這個是空方法,子類在繼承HandlerThread的時候可以重寫這個方法,這樣可以在消息循環真正跑起來之前做一些準備工作,然後再調用Looper.loop(),讓消息循環真正跑起來。
我們繼續看sample code,
Handler handler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.v("test","handleMessage");
return false;
}
});
就是初始化一個Handler對象,將handlerThread的Looper作爲參數專遞給handler,這樣做的作用是handler之後發送的消息就會送到這個handlerThread的子線程,而不是我們通常在使用的MainThread即UI線程。我們這裏重點看一下handlerThread.getLooper()
方法。
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason 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()) {
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;
}
從方法註釋我們知道,只有當線程是live狀態的時候纔可以返回值,否則就返回null,這裏面也有一個鎖,大致邏輯就是如果發現mLoope
r是null
則等待,直到被喚醒,那誰會喚醒它呢?從前面的分析知道,這個mLooper
是在run
方法裏被賦值,也是在run方法裏被賦值後喚醒getLooper
方法中的鎖,這個就實現了只要調用getLooper
方法,就可以獲得子線程looper的目的。
接下來就是用handler調用SendMessage給handlerThread發送消息了,這個中間的原理在之前的:Android Handler消息源碼分析已經講過,這裏不再重複。最後調用handlerThread.quitSafely()
方法退出HandlerThread的消息循環
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
邏輯就是安全的退出消息循環,然後從run()
方法返回,線程結束。handler還有另外一個退出方法就是quit()
,這兩個方法的區別是,quitSafely()
在退出線程之前會分發完消息隊列中剩下的message
,但有個例外,就是通過postDelay
方法發送的延遲消息也不會被分發,,而quit
是直接退出,不管消息隊列中還有沒有消息,至於選擇哪個方法,就看具體使用場景了。好了,就講到這裏,是不是很簡單。