天天看點

android 線程 handle,Android多線程之HandlerThread

@author:小馬快跑

@email:[email protected]

@github:https://github.com/crazyqiang

HandlerThread的介紹及用法

HandlerThread繼承自Thread,内部實作了初始化了Looper,并建立了消息隊列,接着調用了Looper.loop()開啟了消息循環,這樣HandlerThread就可以處理通過Handler傳遞過來的Message了,因為HandlerThread中的run方法是無限循環,當有消息過來時處理消息,沒有消息時就會阻塞。當明确不需要HandlerThread時,可以調用quit或者quitSafely (API 18以上使用)來嘗試終止線程。

先看實作的一個效果圖:

來分析實作代碼,先定義對象:private HandlerThread handlerThread; private Handler mainHandler; private Handler uiHandler;

初始化:handlerThread = new HandlerThread("handler_thread");

handlerThread.start(); //在主線程初始化,傳入的是HandlerThread中的Looper

mainHandler = new Handler(handlerThread.getLooper()) {     @Override

public void handleMessage(Message msg) {         //Handler是在HandlerThread所在的子線程線程中處理Message

switch (msg.what) {             case MSG_UPDATE:                 if (isStop) return;                 try {                     //更新UI

String result = String.valueOf(new Random().nextInt(9000) + 1000);

sendMsg(UI_UPDATE, result, uiHandler);                     //延遲2秒

Thread.sleep(2000);                     //循環發送消息

mainHandler.sendEmptyMessage(MSG_UPDATE);

} catch (InterruptedException e) {

e.printStackTrace();

}                 break;

}

}

};

首先,初始化HandlerThread并通過handlerThread.getLooper()關聯一個在UI線程初始化的mainHandler,這樣就可以通過mainHandler在主線程中向HandlerThread中發送消息了,這裡要注意一下,mainHandler中的handleMessage()方法是在HandlerThread子線程中執行的,為什麼會在子線程中執行呢?因為在初始化mainHandler時傳入的是HandlerThread的Looper,而mainHandler是把消息發送到HandlerThread中去,HandlerThread在執行Looper.loop()方法後會循環取出消息并處理消息,是以mainHandler中的handleMessage()方法是在HandlerThread子線程中執行的,那麼處理完消息後怎麼更新到UI線程呢?//在主線程初始化,傳入的是主線程中的Looper

uiHandler = new Handler(Looper.getMainLooper()) {     @Override

public void handleMessage(Message msg) {         //在主線程中處理Message

switch (msg.what) {             case UI_UPDATE:                 //更新驗證碼

String result = (String) msg.obj;

tv_random.setText(result);                 break;

}

}

};

我們在主線程中初始化了另一個uiHandler 并傳入了主線程的Looper,是以此時最後處理消息的回調方法handleMessage()是在主線程中執行的,當HandlerThread處理完邏輯後,通過uiHandler把結果發到主線程中,就可以愉快地來更新UI了,最後别忘了關閉線程:@Override

protected void onDestroy() {     if (SDK_INT >= 18) {

handlerThread.quitSafely();

} else {

handlerThread.quit();

}     super.onDestroy();

}

HandlerThread API傳回結果HandlerThread備注LoopergetLooper()傳回和HandlerThread關聯的Looper

intgetThreadId()傳回HandlerThread線程的辨別符,參見Process.myTid()

booleanquit()立即停止Looper的循環,即使messageQueue中有消息也不再處理,在調用此方法後,任何傳遞Message的方法 (如sendMessage(Message)) 都将失敗并傳回false

booleanquitSafely()當messageQueue中沒有Message後,在調用此方法後立即終止Looper,任何傳遞Message的方法 (如sendMessage(Message)) 都将失敗并傳回false

voidrun()如果HandlerThread使用單獨的Runnable來構造,将執行此方法

HandlerThread源碼分析public class HandlerThread extends Thread {    int mPriority;    int mTid = -1;

Looper mLooper;    //初始化HandlerThread

public HandlerThread(String name) {        super(name);

mPriority = Process.THREAD_PRIORITY_DEFAULT;

}   //初始化HandlerThread

public HandlerThread(String name, int priority) {        super(name);

mPriority = priority;

}    protected void onLooperPrepared() {

}    @Override

public void run() {

mTid = Process.myTid();        //調用Looper.prepare()初始化Looper 并把Looper放到sThreadLocal中,sThreadLocal可以在不同線程中儲存對象副本

//在Looper的構造方法中就初始化了一個messageQueue,用來存放傳入的消息

Looper.prepare();        synchronized (this) {

mLooper = Looper.myLooper();

notifyAll();

}

Process.setThreadPriority(mPriority);

onLooperPrepared();        //開始循環從messageQueue中取出消息并處理消息,無消息會阻塞,有消息來時就會喚醒

Looper.loop();

mTid = -1;

}    //傳回的即是run方法中産生的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;

}    //立即停止Looper的循環,即使messageQueue中有消息也不再處理,在調用此方法後,任何傳遞Message的

//方法 (如sendMessage(Message)) 都将失敗并傳回false

public boolean quit() {

Looper looper = getLooper();        if (looper != null) {

looper.quit();            return true;

}        return false;

}    //當messageQueue中沒有Message後,在調用此方法後立即終止Looper,任何傳遞Message的

//方法 (如sendMessage(Message)) 都将失敗并傳回false

public boolean quitSafely() {

Looper looper = getLooper();        if (looper != null) {

looper.quitSafely();            return true;

}        return false;

}    public int getThreadId() {        return mTid;

}

}

源碼很簡單,首先HandlerThread繼承了Thread,是以HandlerThread本質上還是一個線程,隻不過在run()方法中又初始化了Looper和MessageQueue,這樣當外界通過Handler向HandlerThread傳入消息後,HandlerThread就會取出消息并處理消息,當沒有消息時就會阻塞。