目錄:

1. 前言
本篇文章是對 Android HandlerThread 類的學(xué)習(xí),通過簡單的例子,及分析源碼來深入學(xué)習(xí)。同時例子將以 Java & Kotlin 兩種代碼形式展示。
1.1 定義
HandlerThread: 一個擁有 Looper 對象的線程。
繼承于 Thread 類,并擁有一個 Looper 對象,可以利用該 Looper 對象來創(chuàng)建 Handler 對象,就像正常的線程一樣,通過調(diào)用 start() 方法來開啟線程。
1.2 使用場景
適用于子線程多任務(wù)的工作場景。如:多個網(wǎng)絡(luò)請求,多個I/O操作
2. 使用方法
其使用方法很簡單:
- 在主線程中新建一個 HandlerThread 對象,然后調(diào)用 start() 方法啟動該線程。
- 創(chuàng)建一個主線程Handler 對象,關(guān)聯(lián)APP主Looper對象,用于子線程與主線程之間的溝通。
- 創(chuàng)建一個工作線程Handler 對象,關(guān)聯(lián) HandlerThread 的 Looper 對象。
- 發(fā)送消息給工作線程,工作線程Handler 接收消息,并處理消息,然后調(diào)用主線程。Handler,發(fā)送信息給主線程,通知主線程做UI工作。
- 當對應(yīng)的 Activity 銷毀時,退出 HandlerThread,終止消息循環(huán)。
比如:我們用兩個 ProgressBar 來模擬在子線程中進行下載任務(wù),點擊按鈕開始下載,ProgressBar 的進度代表著下載進度。
如下所示:

2.1 Java版本
具體代碼如下:
public class HandlerThreadActivity extends AppCompatActivity {
private final int SET_PROGRESS_BAR_1 = 1;
private final int SET_PROGRESS_BAR_2 = 2;
private HandlerThread myHandlerThread;
private Handler mWorkHandler, mMainHandler;
private ProgressBar progressBar1, progressBar2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread);
TextView titleTv = findViewById(R.id.title_tv);
titleTv.setText("HandlerThread");
progressBar1 = findViewById(R.id.progress_bar_1);
progressBar2 = findViewById(R.id.progress_bar_2);
Button startBtn1 = findViewById(R.id.start_progress_bar_1_btn);
Button startBtn2 = findViewById(R.id.start_progress_bar_2_btn);
//創(chuàng)建HandlerThread對象
myHandlerThread = new HandlerThread("myHandlerThread");
//啟動線程
myHandlerThread.start();
//創(chuàng)建主線程Handler,關(guān)聯(lián)APP的主Looper對象
mMainHandler = new Handler(getMainLooper());
//創(chuàng)建工作線程Handler,關(guān)聯(lián)HandlerThread的Looper對象,所以它無法與主線程通訊
mWorkHandler = new Handler(myHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case SET_PROGRESS_BAR_1:
//設(shè)置Progress Bar 1
for (int i = 1; i <= 4; i++) {
try {
//模擬耗時工作
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
final int progressSchedule = I;
//在工作線程中,通過主線程Handler, 傳遞信息給主線程,通知主線程處理UI工作。
mMainHandler.post(new Runnable() {
@Override
public void run() {
progressBar1.setProgress(progressSchedule);
}
});
}
break;
case SET_PROGRESS_BAR_2:
//設(shè)置Progress Bar 2
for (int i = 1; i <= 4; i++) {
try {
//模擬耗時工作
Thread.sleep(1300);
} catch (InterruptedException e) {
e.printStackTrace();
}
final int progressSchedule2 = I;
//在工作線程中,通過主線程Handler, 傳遞信息給主線程,通知主線程處理UI工作。
mMainHandler.post(new Runnable() {
@Override
public void run() {
progressBar2.setProgress(progressSchedule2);
}
});
}
break;
default:
break;
}
}
};
startBtn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//通過工作線程Handler,mWorkHandler發(fā)送處理 progress bar 1 的信息給工作線程。
Message msg = new Message();
msg.what = SET_PROGRESS_BAR_1;
mWorkHandler.sendMessage(msg);
}
});
startBtn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//通過工作線程Handler mWorkHandler發(fā)送處理 progress bar 2 的信息給工作線程。
Message msg = new Message();
msg.what = SET_PROGRESS_BAR_2;
mWorkHandler.sendMessage(msg);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
myHandlerThread.quit();
}
}
2.2 Kotlin版本
Kotlin 版本代碼如下:
class TestHandlerThreadActivity : AppCompatActivity(), View.OnClickListener {
var mHandlerThread: HandlerThread? = null
var mMainHandler: Handler? = null
var mWorkHandler: WorkHandler? = null
override fun onClick(v: View?) {
when (v?.id) {
R.id.handlerThreadStart1Btn -> mWorkHandler?.obtainMessage(1)?.sendToTarget()
R.id.handlerThreadStart2Btn -> mWorkHandler?.obtainMessage(2)?.sendToTarget()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test_handler_thread)
mMainHandler = Handler(Looper.getMainLooper())
mHandlerThread = HandlerThread("JereTest")
mHandlerThread!!.start()
mWorkHandler = WorkHandler(mHandlerThread!!.looper)
handlerThreadStart1Btn.setOnClickListener(this)
handlerThreadStart2Btn.setOnClickListener(this)
}
inner class WorkHandler(looper: Looper) : Handler(looper) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
when (msg.what) {
1 -> {
for (i in 1..5) {
Thread.sleep(1000)
mMainHandler?.post { handlerThreadProgressBar1.progress = I }
}
}
2 -> {
for (j in 1..5) {
Thread.sleep(1000)
mMainHandler?.post { handlerThreadProgressBar2.progress = j }
}
}
}
}
}
override fun onDestroy() {
super.onDestroy()
mHandlerThread?.quit()
}
}
3. 源碼分析
按使用步驟來分析源碼:

步驟一:在主線程中新建一個 HandlerThread 對象,然后調(diào)用 start() 方法啟動該線程。
//創(chuàng)建 HandlerThread 對象
myHandlerThread = new HandlerThread("myHandlerThread");
//啟動線程,執(zhí)行 run() 方法
myHandlerThread.start();
//創(chuàng)建 HandlerThread 對象,看其構(gòu)造函數(shù)
/**
* HandlerThread的構(gòu)造函數(shù)
* @param name,線程名字是我們傳入的,用于標記改線程
*/
public HandlerThread(String name) {
super(name);
//指定該線程的優(yōu)先級為標準線程優(yōu)先級
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
//啟動線程
@Override
public void run() {
//獲得線程標識符
mTid = Process.myTid();
//為該線程創(chuàng)建一個 Looper 對象,具體見下:
Looper.prepare();
synchronized (this) {
//獲取通過 Looper.prepare() 方法創(chuàng)建的 Looper 對象。
mLooper = Looper.myLooper();
//喚醒那些為創(chuàng)建Looper對象而阻塞的線程
notifyAll();
}
//設(shè)置該線程的優(yōu)先級,比如設(shè)置為標準線程優(yōu)先級
Process.setThreadPriority(mPriority);
//消息循環(huán)前做的處理,即:如果想在消息循環(huán)前做一些處理,則需要復(fù)寫onLooperPreopared()方法。
onLooperPrepared();
//循環(huán)該Looper對象中的消息隊列
Looper.loop();
mTid = -1;
}
步驟二:創(chuàng)建一個主線程Handler 對象,關(guān)聯(lián)APP主Looper對象,用于子線程與主線程之間的溝通。
//創(chuàng)建主線程Handler,關(guān)聯(lián)APP的主Looper對象
mMainHandler = new Handler(getMainLooper());
其具體源碼分析內(nèi)容請看另外一篇文章Android Handler 深入學(xué)習(xí)及源碼分析
步驟三. 創(chuàng)建一個工作線程Handler 對象,關(guān)聯(lián) HandlerThread 的 Looper 對象。
其具體實現(xiàn)方法如下:
//創(chuàng)建工作線程Handler,關(guān)聯(lián)HandlerThread的Looper對象,所以它無法與主線程通訊
mWorkHandler = new Handler(myHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
···略···
}
};
通過 getLooper() 方法獲取 HandlerThread 的 Looper 對象,其源碼如下:
/**
* 該方法返回該線程所關(guān)聯(lián)的Looper對象。
* 如果這個線程沒有啟動,或者由于任何原因isAlive()返回false,那么這個方法將返回null。
* 如果這個線程已經(jīng)啟動,這個方法將阻塞,直到looper被初始化。
* @return The looper.
*/
public Looper getLooper() {
//線程未激活,返回 null
if (!isAlive()) {
return null;
}
//如果該線程已經(jīng)啟動,則阻塞該方法,直到創(chuàng)建好Looper對象。
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
步驟四:發(fā)送消息給工作線程,工作線程Handler 接收消息,并處理消息,然后調(diào)用主線程Handler,發(fā)送信息給主線程,通知主線程做UI工作。
Handler 通過 sendMessage(Msg) 及 post(Runnable) 方法傳遞消息,本篇博客不展開具體分析,具體源代碼分析見上一篇博客Android Handler 深入學(xué)習(xí)及源碼分析
步驟五:當對應(yīng)的 Activity 銷毀時,退出 HandlerThread,終止消息循環(huán)。
當當前 Activity 退出銷毀時,復(fù)寫 onDestry() 方法,退出 HandlerThread,如:
@Override
protected void onDestroy() {
super.onDestroy();
myHandlerThread.quit();
}
通過 quit() 方法退出 HandlerThread,終止消息循環(huán),具體源代碼分析,見下:
/**
* 終止 Handler 關(guān)聯(lián)的 looper 消息循環(huán),不在處理消息隊列中的任何消息。
* 當 looper 被停止后再嘗試請求消息入消息隊列,會失敗,比如:sendMessage(Message) 會返回 false。
* 使用該方法可能不安全,因為 looper 在沒有循環(huán)分發(fā)完所有消息時就被停止了。
* 考慮使用quitsafe() 方法來代替,以確保所有未完成的工作以有序的方式完成。
*
* @return 如果Looper停止消息循環(huán),返回True; 如果線程尚未開始運行,則返回false。
*/
public boolean quit() {
//獲取 Handler 所關(guān)聯(lián)的 Looper 對象。
Looper looper = getLooper();
//如果 Looper 不為空,停止其消息循環(huán),返回true
if (looper != null) {
looper.quit();
return true;
}
//如果 Looper 為空,即現(xiàn)場還未開始運行,返回 false。
return false;
}
/**
* 安全的終止 Handler 關(guān)聯(lián)的 Looper 消息循環(huán),處理消息隊列中所有已到期的消息,而未到期的掛起的延遲消息將不被傳遞
* 處理完消息隊列中的所有消息后立即停止 Looper 消息循環(huán)
* 當 looper 被停止后再嘗試請求消息入消息隊列,會失敗,比如:sendMessage(Message) 會返回 false。
* 如果線程還未開始或已經(jīng)結(jié)束(getLooper 返回 null),返回false;另外,當 Looper 被要求 quit() 停止消息循環(huán)時,返回true。
*
* @return 如果Looper停止消息循環(huán),返回True; 如果線程尚未開始運行,則返回false。
*/
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
//
looper.quitSafely();
return true;
}
return false;
}
至此 HandlerThread 的源碼也就分析結(jié)束了。
其實分享文章的最大目的正是等待著有人指出我的錯誤,如果你發(fā)現(xiàn)哪里有錯誤,請毫無保留的指出即可,虛心請教。
另外,如果你覺得文章不錯,對你有所幫助,請給我點個贊,就當鼓勵,謝謝~Peace~!