Android HandlerThread詳解(源碼分析)

目錄:

目錄

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. 使用方法

其使用方法很簡單:

  1. 在主線程中新建一個 HandlerThread 對象,然后調(diào)用 start() 方法啟動該線程。
  2. 創(chuàng)建一個主線程Handler 對象,關(guān)聯(lián)APP主Looper對象,用于子線程與主線程之間的溝通。
  3. 創(chuàng)建一個工作線程Handler 對象,關(guān)聯(lián) HandlerThread 的 Looper 對象。
  4. 發(fā)送消息給工作線程,工作線程Handler 接收消息,并處理消息,然后調(diào)用主線程。Handler,發(fā)送信息給主線程,通知主線程做UI工作。
  5. 當對應(yīng)的 Activity 銷毀時,退出 HandlerThread,終止消息循環(huán)。

比如:我們用兩個 ProgressBar 來模擬在子線程中進行下載任務(wù),點擊按鈕開始下載,ProgressBar 的進度代表著下載進度。
如下所示:


HandlerThread子線程執(zhí)行多任務(wù).gif

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使用方法

步驟一:在主線程中新建一個 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~!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容