【Android】Handler與HandlerThread

1. HandlerThread的本質(zhì)

  • 通過(guò)繼承Thread類,創(chuàng)建一個(gè)帶有Looper對(duì)象的新工作線程,不需要手動(dòng)調(diào)用Looper.prepare()Looper.loop()方法
  • 通過(guò)封裝Handler類,快速創(chuàng)建handler并與其他線程進(jìn)行交互

我們首先將簡(jiǎn)單介紹Handler,然后應(yīng)用Handler+Thread來(lái)實(shí)現(xiàn)多線程通信,最后講解如何通過(guò)HandlerThread來(lái)實(shí)現(xiàn)多線程通信。

2. Handler

用于線程之間的通信,如將工作線程中需要更新UI的信息傳遞到主線程,從而實(shí)現(xiàn)“工作線程對(duì)UI的更新”

Handler的工作流程

在這個(gè)過(guò)程中用到的組件有:Handler,Looper,MessageQueueMessage

  • Looper: 消息隊(duì)列和Handler的通信媒介,進(jìn)行消息循環(huán)
    • 消息獲取:循環(huán)取出消息隊(duì)列中的消息
    • 消息分發(fā):將消息分發(fā)給對(duì)應(yīng)的Handler,遵循“誰(shuí)發(fā)送,誰(shuí)處理”的原則
  • MessageQueue:
    • 一種數(shù)據(jù)結(jié)構(gòu),存儲(chǔ)Handler發(fā)送過(guò)來(lái)的消息
  • Message: 需要在某一線程執(zhí)行的操作信息
    • obj為其攜帶的傳遞對(duì)象
    • what為消息標(biāo)識(shí)
  • 整體流程
    • Handler發(fā)送Msg,這個(gè)消息被存儲(chǔ)在該線程的MessageQueue,Looper不斷循環(huán)取出消息隊(duì)列中的Msg,并分發(fā)給對(duì)應(yīng)的Handler進(jìn)行處理。
  • 一個(gè)線程會(huì)配備一個(gè)Looper,一個(gè)MessageQueue, 但是可以擁有無(wú)數(shù)個(gè)Handler
  • 主線程中的Looper已經(jīng)幫我們配置好了,所以我們并不需要自己實(shí)現(xiàn)Looper的相關(guān)操作,但是在其他線程如果想要使用Looper,需要自己進(jìn)行配置。
  • Handler會(huì)與線程進(jìn)行綁定,一個(gè)Handler只能與一個(gè)線程綁定(為這個(gè)線程發(fā)送和處理消息),但是一個(gè)線程可以與多個(gè)Handler進(jìn)行綁定

3. Handler + Thread 實(shí)現(xiàn)線程

3.1 sendMessage + handleMessage

  • 在新建子線程中執(zhí)行耗時(shí)操作,并新建Message對(duì)象sendMessage
object: Thread(){
            override fun run() {
                try {
                    sleep(6000)
                    addDataToServiceList()
                }catch (e: InterruptedException) {
                    e.printStackTrace()
                }

                val msg = Message.obtain()
                msg.what = 1
                handler.sendMessage(msg)
            }
        }.start()
  • 在主線程中創(chuàng)建Handler對(duì)象,并handleMessage,根據(jù)Message的what屬性來(lái)確定操作
handler = object :Handler(){
       override fun handleMessage(msg: Message) {
                when(msg.what){
                    1-> setRecyclerView(mRecyclerView)
                }
            }
        }

3.2 post

  • 新建子線程,在執(zhí)行完try catch之后
  • 執(zhí)行handler.post,在其中Runnable的run方法中執(zhí)行得到數(shù)據(jù)后的操作
handler = Handler()
        
object: Thread(){
            override fun run() {
                try {
                    sleep(6000)
                    addDataToServiceList()
                }catch (e: InterruptedException) {
                    e.printStackTrace()
                }
                handler.post(Runnable {
                    setRecyclerView(mRecyclerView)
                })
            }
        }.start()

4. HandlerThread

4.1 工作原理

  • 通過(guò)繼承Looper類,創(chuàng)建一個(gè)帶有Looper對(duì)象的新工作線程
  • 通過(guò)封裝Handler類,快速創(chuàng)建handler并與其他線程進(jìn)行交互

4.2 實(shí)現(xiàn)步驟

  • 創(chuàng)建HandlerThread實(shí)例對(duì)象:需要傳入一個(gè)線程名字的參數(shù),用來(lái)標(biāo)記該線程
  • 因?yàn)?code>HandlerThread繼承了Thread類,所以直接HandlerThread.start()就可以啟動(dòng)一個(gè)線程
  • 創(chuàng)建Handler并實(shí)現(xiàn)handleMessage方法
  • handler發(fā)送消息
  • 結(jié)束線程:HandlerThread.quit()
// 步驟1:創(chuàng)建HandlerThread實(shí)例對(duì)象
// 傳入?yún)?shù) = 線程名字,作用 = 標(biāo)記該線程
   HandlerThread mHandlerThread = new HandlerThread("handlerThread");

// 步驟2:?jiǎn)?dòng)線程
   mHandlerThread.start();

// 步驟3:創(chuàng)建工作線程Handler & 復(fù)寫(xiě)handleMessage()
// 作用:關(guān)聯(lián)HandlerThread的Looper對(duì)象、實(shí)現(xiàn)消息處理操作 & 與其他線程進(jìn)行通信
// 注:消息處理操作(HandlerMessage())的執(zhí)行線程 = mHandlerThread所創(chuàng)建的工作線程中執(zhí)行
  Handler workHandler = new Handler( mHandlerThread.getLooper() ) {
            @Override
            public boolean handleMessage(Message msg) {
                ...//消息處理
                return true;
            }
        });

// 步驟4:使用工作線程Handler向工作線程的消息隊(duì)列發(fā)送消息
// 在工作線程中,當(dāng)消息循環(huán)時(shí)取出對(duì)應(yīng)消息 & 在工作線程執(zhí)行相關(guān)操作
  // a. 定義要發(fā)送的消息
  Message msg = Message.obtain();
  msg.what = 2; //消息的標(biāo)識(shí)
  msg.obj = "B"; // 消息的存放
  // b. 通過(guò)Handler發(fā)送消息到其綁定的消息隊(duì)列
  workHandler.sendMessage(msg);

// 步驟5:結(jié)束線程,即停止線程的消息循環(huán)
  mHandlerThread.quit();

5. 參考文檔

http://www.itdecent.cn/p/9c10beaa1c95
http://www.itdecent.cn/p/e172a2d58905
https://www.raywenderlich.com/5466-threading-with-handlerthread-in-android
https://blog.csdn.net/fdsafwagdagadg6576/article/details/110293636

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

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

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