Android中Handler、Thread、HandlerThread三者的區(qū)別
一、前期知識(shí)儲(chǔ)備
(1)Handler類(lèi),上官方文檔,Handler
public class Handler.A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.
(2)Thread類(lèi),上官方文檔,Thread
public class Thread. extends Object implements Runnable.A thread is a thread of execution in a program. The Java Virtual Machine allows an application to have multiple threads of execution running concurrently.
Every thread has a priority. Threads with higher priority are executed in preference to threads with lower priority. Each thread may or may not also be marked as a daemon. When code running in some thread creates a new Thread object, the new thread has its priority initially set equal to the priority of the creating thread, and is a daemon thread if and only if the creating thread is a daemon.
(3)HandlerThread類(lèi),上官方文檔,HandlerThread
public class HandlerThread. extends Thread. Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.
二、三者的區(qū)別
①Handler:在android中負(fù)責(zé)發(fā)送和處理消息,通過(guò)它可以實(shí)現(xiàn)其他支線(xiàn)線(xiàn)程與主線(xiàn)程之間的消息通訊。
②Thread:Java進(jìn)程中執(zhí)行運(yùn)算的最小單位,亦即執(zhí)行處理機(jī)調(diào)度的基本單位。某一進(jìn)程中一路單獨(dú)運(yùn)行的程序。
③HandlerThread:一個(gè)繼承自Thread的類(lèi)HandlerThread,Android中沒(méi)有對(duì)Java中的Thread進(jìn)行任何封裝,而是提供了一個(gè)繼承自Thread的類(lèi)HandlerThread類(lèi),這個(gè)類(lèi)對(duì)Java的Thread做了很多便利的封裝。
———————————————————我是分割線(xiàn)—————————————————————
其實(shí)這個(gè)問(wèn)題,最主要的關(guān)注點(diǎn)還是落在了HandlerThread類(lèi)上,那么這個(gè)類(lèi)到底有什么作用,所謂的便利封裝又體現(xiàn)在哪里?
觀察HandlerThread的官方文檔的兩句:①Thread. Handy class for starting a new thread that has a looper.②The looper can then be used to create handler classes.
釋義:HandlerThread對(duì)象start后可以獲得其Looper對(duì)象,并且使用這個(gè)Looper對(duì)象實(shí)例Handler,之后Handler就可以運(yùn)行在其他線(xiàn)程中了。
———————————————————我是分割線(xiàn)—————————————————————
那么Handler和Looper到底是什么關(guān)系,為什么HandlerThread要做這樣的處理?觀看下圖:
Andriod提供了 Handler 和 Looper 來(lái)滿(mǎn)足線(xiàn)程間的通信。 Handler 先進(jìn)先出原則。 Looper 類(lèi)用來(lái)管理特定線(xiàn)程內(nèi)對(duì)象之間的消息交換 (MessageExchange) 。
1)Looper: 一個(gè)線(xiàn)程可以產(chǎn)生一個(gè) Looper 對(duì)象,由它來(lái)管理此線(xiàn)程里的 MessageQueue( 消息隊(duì)列 ) 和對(duì)消息進(jìn)行循環(huán)。
2)Handler: 你可以構(gòu)造 Handler 對(duì)象來(lái)與 Looper 溝通,以便 push 新消息到 MessageQueue 里 ; 或者接收 Looper 從 Message Queue 取出 所送來(lái)的消息。
3) Message Queue( 消息隊(duì)列 ): 用來(lái)存放線(xiàn)程放入的消息。
4) Message:是線(xiàn)程間通訊的消息載體。兩個(gè)碼頭之間運(yùn)輸貨物,Message充當(dāng)集裝箱的功能,里面可以存放任何你想傳遞的消息。
看到這里就明白了為什么:如果一個(gè)線(xiàn)程要處理消息,那么它必須擁有自己的Looper,并不是Handler在哪里創(chuàng)建,就可以在哪里處理消息。
注:對(duì)應(yīng)關(guān)系Thread(1):Looper(1):MessageQueen(1):Handler(n).
三、HandlerThread的使用
正如前面所說(shuō),線(xiàn)程間通信的時(shí)候,比如Android中常見(jiàn)的更新UI,涉及到的是子線(xiàn)程和主線(xiàn)程之間的通信,實(shí)現(xiàn)方式就是Handler+Looper,但是要自己手動(dòng)操作Looper,不推薦,所以谷歌封裝了HandlerThread類(lèi)(類(lèi)似于AsyncTask類(lèi))。
上代碼,具體實(shí)現(xiàn):
public class MainActivity extends AppCompatActivity { Handler mainHandler,workHandler; HandlerThread mHandlerThread; TextView text; Button button1,button2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); text = (TextView) findViewById(R.id.text1); // 創(chuàng)建與主線(xiàn)程關(guān)聯(lián)的Handler mainHandler = new Handler(); /** * 步驟①:創(chuàng)建HandlerThread實(shí)例對(duì)象 * 傳入?yún)?shù) = 線(xiàn)程名字,作用 = 標(biāo)記該線(xiàn)程 */ mHandlerThread = new HandlerThread("handlerThread"); /** * 步驟②:?jiǎn)?dòng)線(xiàn)程 */ mHandlerThread.start(); /** * 步驟③:創(chuàng)建工作線(xiàn)程Handler & 復(fù)寫(xiě)handleMessage() * 作用:關(guān)聯(lián)HandlerThread的Looper對(duì)象、實(shí)現(xiàn)消息處理操作 & 與其他線(xiàn)程進(jìn)行通信 * 注:消息處理操作(HandlerMessage())的執(zhí)行線(xiàn)程 = mHandlerThread所創(chuàng)建的工作線(xiàn)程中執(zhí)行 */ workHandler = new Handler(mHandlerThread.getLooper()){ @Override public void handleMessage(Message msg) { //設(shè)置了兩種消息處理操作,通過(guò)msg來(lái)進(jìn)行識(shí)別 switch(msg.what){ case 1: try { //延時(shí)操作 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // 通過(guò)主線(xiàn)程Handler.post方法進(jìn)行在主線(xiàn)程的UI更新操作 mainHandler.post(new Runnable() { @Override public void run () { text.setText("第一次執(zhí)行"); } }); break; case 2: try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } mainHandler.post(new Runnable() { @Override public void run () { text.setText("第二次執(zhí)行"); } }); break; default: break; } } }; /** * 步驟④:使用工作線(xiàn)程Handler向工作線(xiàn)程的消息隊(duì)列發(fā)送消息 * 在工作線(xiàn)程中,當(dāng)消息循環(huán)時(shí)取出對(duì)應(yīng)消息 & 在工作線(xiàn)程執(zhí)行相關(guān)操作 */ button1 = (Button) findViewById(R.id.button1); button1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Message msg = Message.obtain(); msg.what = 1; //消息的標(biāo)識(shí) msg.obj = "A"; // 消息的存放 // 通過(guò)Handler發(fā)送消息到其綁定的消息隊(duì)列 workHandler.sendMessage(msg); } }); button2 = (Button) findViewById(R.id.button2); button2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Message msg = Message.obtain(); msg.what = 2; msg.obj = "B"; workHandler.sendMessage(msg); } }); } @Override protected void onDestroy() { super.onDestroy(); mHandlerThread.quit(); // 退出消息循環(huán) workHandler.removeCallbacks(null); // 防止Handler內(nèi)存泄露 清空消息隊(duì)列 } }
從上面代碼可以看出,HandlerThread繼承于Thread,所以它本質(zhì)就是個(gè)Thread。與普通Thread的差別就在于,然后在內(nèi)部直接實(shí)現(xiàn)了Looper的實(shí)現(xiàn),這是Handler消息機(jī)制必不可少的。有了自己的looper,可以讓我們?cè)谧约旱木€(xiàn)程中分發(fā)和處理消息。如果不用HandlerThread的話(huà),需要手動(dòng)去調(diào)用Looper.prepare()和Looper.loop()這些方法。
// 子線(xiàn)程中創(chuàng)建新的Handler 沒(méi)有使用HandlerThread new Thread () { @Override public void run() { Looper.prepare(); Hnadler handler = new Handler(); Looper.loop(); } }
提供一些其他Android消息機(jī)制分析,幫助理解讀者理解:
①Handler是Android消息機(jī)制的上層接口,通過(guò)它可以輕松地將一個(gè)任務(wù)切換到Handler所在的線(xiàn)程中去執(zhí)行,該線(xiàn)程既可以是主線(xiàn)程,也可以是子線(xiàn)程,要看構(gòu)造Handler時(shí)使用的構(gòu)造方法中傳入的Looper位于哪里;
②Handler的運(yùn)行需要底層的MessageQueue和Looper的支撐,Handler創(chuàng)建的時(shí)候會(huì)采用當(dāng)前線(xiàn)程的Looper來(lái)構(gòu)造消息循環(huán)系統(tǒng),而線(xiàn)程默認(rèn)是沒(méi)有Looper的,如果需要使用Handler就必須為線(xiàn)程創(chuàng)建Looper;
③上述代碼中的第一個(gè)Handler-mainHandler,實(shí)例化的時(shí)候,直接在onCreate()方法中new出了實(shí)例,其實(shí)是其已經(jīng)在主線(xiàn)程中了,主線(xiàn)程-ActivityThread,ActivityThread被創(chuàng)建時(shí)就會(huì)初始化Looper,這就是主線(xiàn)程中默認(rèn)可以直接使用Handler的原因;
④上述代碼中的第二個(gè)Handler-workHandler,它在實(shí)例化的時(shí)候,參數(shù)傳入了 mHandlerThread.getLooper() ,注意,這個(gè)Handler使用的就不是主線(xiàn)程的Looper了,而是子線(xiàn)程的Looper,HandlerThread在調(diào)用start()方法之后,就可以獲取到子線(xiàn)程的Looper,然后將其傳入workHandler的構(gòu)造方法中,那么此時(shí)的workHandler就會(huì)運(yùn)行在子線(xiàn)程中,用于處理耗時(shí)操作。
⑤Handler的工作原理:Handler創(chuàng)建時(shí)會(huì)采用當(dāng)前線(xiàn)程的Looper來(lái)構(gòu)建內(nèi)部消息循環(huán)系統(tǒng),如果當(dāng)前線(xiàn)程沒(méi)有Looper,那么就會(huì)報(bào)錯(cuò)“Can`t create handler inside thread that has not called Looper.prepare()”解決方法有兩個(gè):為當(dāng)前線(xiàn)程創(chuàng)建Looper即可,像上述代碼中workHandler,或者在一個(gè)有Looper的線(xiàn)程中創(chuàng)建Handler也行,就像上述代碼中的mainHandler一樣;
⑥調(diào)用Handler的post方法會(huì)將一個(gè)Runnable投遞到Handler內(nèi)部的Looper中去處理,也可以通過(guò)Handler的send方法來(lái)發(fā)送一個(gè)消息,這個(gè)消息同樣會(huì)在Looper中去處理。其實(shí)post方法最終也是通過(guò)send方法來(lái)完成的。每當(dāng)Looper發(fā)現(xiàn)有新消息到來(lái)時(shí),就會(huì)處理這個(gè)消息,最終消息中的Runnable的run方法或者Handler的handleMessage方法就會(huì)被調(diào)用。注意Looper是運(yùn)行在創(chuàng)建Handler所在的線(xiàn)程中的,這樣一來(lái)Handler中的業(yè)務(wù)邏輯就被切換到創(chuàng)建Handler所在的線(xiàn)程中去執(zhí)行了;
⑦Looper的工作原理:Looper在Android的消息機(jī)制中扮演著消息循環(huán)的角色,具體來(lái)說(shuō)就是它會(huì)不停地從MessageQueue中查看是否有新消息,如果有新消息就會(huì)立刻處理,否則就一直阻塞在那里。注意關(guān)注一些重要的Looper的方法:
- Looper.prepare()-為當(dāng)前線(xiàn)程創(chuàng)建一個(gè)Looper;
- Looper.loop()-開(kāi)啟消息循環(huán),只有調(diào)用該方法,消息循環(huán)系統(tǒng)才會(huì)開(kāi)始循環(huán);
- Looper.prepareMainLooper()-為主線(xiàn)程也就是ActivityThread創(chuàng)建Looper使用;
- Looper.getMainLooper()-通過(guò)該方法可以在任意地方獲取到主線(xiàn)程的Looper;
- Looper.quit() Looper.quitSafely()-退出Looper,自主創(chuàng)建的Looper建議在不使用的時(shí)候退出
⑧ActivityThread主線(xiàn)程通過(guò)ApplicationThread和AMS進(jìn)行進(jìn)程間通信
到此這篇關(guān)于Android中Handler、Thread、HandlerThread三者的區(qū)別的文章就介紹到這了,更多相關(guān)Android中Handler、Thread、HandlerThread三者的區(qū)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android開(kāi)發(fā)之登錄驗(yàn)證實(shí)例教程
這篇文章主要介紹了Android開(kāi)發(fā)之登錄驗(yàn)證實(shí)現(xiàn)方法,包括發(fā)送數(shù)據(jù)、服務(wù)器端驗(yàn)證、配置文件等,需要的朋友可以參考下2014-08-08Android Studio 中運(yùn)行 groovy 程序的方法圖文詳解
這篇文章主要介紹了Android Studio 中 運(yùn)行 groovy 程序的方法,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03Android ScrollView實(shí)現(xiàn)反彈效果的實(shí)例
這篇文章主要介紹了 Android ScrollView實(shí)現(xiàn)反彈效果的實(shí)例的相關(guān)資料,這里自定義scrollview 并實(shí)現(xiàn)反彈效果,需要的朋友可以參考下2017-07-07Android 中 android.view.WindowLeaked的解決辦法
這篇文章主要介紹了Android 中 android.view.WindowLeaked的解決辦法的相關(guān)資料,需要的朋友可以參考下2017-05-05Android自定義豎排TextView實(shí)現(xiàn)實(shí)例
這篇文章主要介紹了Android自定義豎排TextView實(shí)現(xiàn)實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-05-05使用Flutter實(shí)現(xiàn)一個(gè)走馬燈布局的示例代碼
這篇文章主要介紹了使用 Flutter 實(shí)現(xiàn)一個(gè)走馬燈布局的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11Android 修改Preferences默認(rèn)樣式的步驟
這篇文章主要介紹了Android 修改Preferences默認(rèn)樣式的步驟,幫助大家更好的理解和學(xué)習(xí)使用Android開(kāi)發(fā),感興趣的朋友可以了解下2021-04-04android判斷一個(gè)Activity是否處于棧頂?shù)膶?shí)例
下面小編就為大家分享一篇android判斷一個(gè)Activity是否處于棧頂?shù)膶?shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-03-03