【Android】Handler 机制 ( Handler | Message | Looper | MessageQueue )
文章目錄
- I . Handler 機(jī)制簡(jiǎn)介
- II . Handler 機(jī)制 Handler Message Looper MessageQueue 四組件對(duì)應(yīng)關(guān)系
- III . Handler ( 消息處理者 )
- IV . Looper ( 消息遍歷者 )
- V . Looper 子線程
- VI . Handler 發(fā)送 消息 種類
- VII . Handler 機(jī)制總結(jié)
I . Handler 機(jī)制簡(jiǎn)介
Handler 機(jī)制是 Android 中最重要的 異步通信 機(jī)制 ;
1 . Handler 機(jī)制作用 : 將需要執(zhí)行的任務(wù)分配給其它線程 ;
① 子線程更新 UI : 在子線程中更新 UI , 就是在子線程中將刷新 UI 的任務(wù)分配給了主線程 ; ( 子線程刷新 UI 會(huì)崩潰 )
② 主線程網(wǎng)絡(luò)操作 : 在主線程中 , 將網(wǎng)絡(luò)通信等耗時(shí)的操作分配給子線程 ( 該子線程需要轉(zhuǎn)成 Looper 線程 ) , 避免 UI 卡頓 ; ( 主線程訪問(wèn)網(wǎng)絡(luò)會(huì)崩潰 )
2 . Handler 機(jī)制中涉及到的組件 :
① Handler ( 消息處理者 ) : 定義具體的代碼操作邏輯 , 處理收到消息 ( Message ) 后的具體操作 ;
② Message ( 消息 ) : 定義具體消息 , 其中可以封裝不同的變量 , 為 Handler 指定操作的類型 , 或執(zhí)行操作所需的數(shù)據(jù) ;
③ Looper ( 消息遍歷者 ) : 消息的遍歷者 , 遍歷 MessageQueue 中的消息 , 分發(fā)給 Handler 處理 ;
④ MessageQueue ( 消息隊(duì)列 ) : 封裝在 Looper 中 , 每個(gè) Looper 中封裝了一個(gè) MessageQueue , 是 Looper 消息遍歷的重要組件 , 用戶不直接調(diào)用該組件 ;
3 . Handler 機(jī)制中的 封閉性 與 線程交互 :
① 線程內(nèi)部相對(duì)封閉的運(yùn)行系統(tǒng) : 整個(gè) Looper 線程內(nèi)部是一個(gè)封閉運(yùn)行的系統(tǒng) , Looper 一直不停的再遍歷 MessageQueue , 將 消息 或 操作 取出 , 交給 Handler 執(zhí)行 ;
② 線程交互 : Handler 還有另外一個(gè)職責(zé)就是負(fù)責(zé)與外部線程的交互 , 在外部線程中調(diào)用 Handler 將消息回傳給本 Looper 線程 , 放入 MessageQueue 隊(duì)列中 ;
4 . Message ( 消息 ) 的運(yùn)行路徑 ( 重點(diǎn) ) : 在外部線程中 , 調(diào)用 Looper 線程的 Handler 成員 , 將 Message ( 消息 ) 發(fā)送給 Looper 線程中的 MessageQueue ( 消息隊(duì)列 ) , 然后 Looper 輪詢?cè)?消息隊(duì)列時(shí) , 又將該消息交給 Handler 進(jìn)行處理 ;
Message -> Handler ( 發(fā)送 ) -> MessageQueue ( 存儲(chǔ) ) -> Looper ( 輪詢 ) -> Handler ( 執(zhí)行 )
II . Handler 機(jī)制 Handler Message Looper MessageQueue 四組件對(duì)應(yīng)關(guān)系
Handler , Message , Looper , MessageQueue 四組件對(duì)應(yīng)關(guān)系 :
Handler 機(jī)制中的上述四者的對(duì)應(yīng)關(guān)系 : 一個(gè)線程中只能有一個(gè) Looper 及 Looper 中封裝的 MessageQueue , 每個(gè) Looper 可以為多個(gè) Handler 調(diào)度消息 , Message 消息可以有無(wú)數(shù)個(gè) ;
Looper 是 線程本地存儲(chǔ)的對(duì)象 ( ThreadLocal ) , 一個(gè)線程只能存在一個(gè) , MessageQueue ( 消息隊(duì)列 ) 定義在 Looper 內(nèi)部 , 每個(gè) Looper 中只定義了一個(gè) MessageQueue ( 消息隊(duì)列 ) , 因此每個(gè)線程也只能有一個(gè) MessageQueue ;
線程 與 Looper ( 消息遍歷者 ) 是一對(duì)一關(guān)系 , Looper ( 消息遍歷者 ) 與 MessageQueue ( 消息隊(duì)列 ) 是一對(duì)一的關(guān)系 , Looper ( 消息遍歷者 ) 與 Handler ( 消息處理者 ) 是一對(duì)多的關(guān)系 , Message ( 消息 ) 可以有很多 ;
III . Handler ( 消息處理者 )
1 . Handler 創(chuàng)建 : 這里注意 只能在 Looper 線程中創(chuàng)建 Handler , 普通線程不能創(chuàng)建 Handler ;
① 主線程 : 主線程中可以直接創(chuàng)建 Handler , 因?yàn)樵邳c(diǎn)擊應(yīng)用圖標(biāo)后就會(huì) 啟動(dòng)主線程 ActivityThread , 此時(shí)就已經(jīng)將 Looper 實(shí)例化好了 , 因此我們?cè)?Activity 中 , 可以任意創(chuàng)建多個(gè) Handler , 并直接使用 ;
public final class ActivityThread {...public static void main(String[] args) {...Looper.prepareMainLooper();//創(chuàng)建 ActivityThread 線程, 并運(yùn)行ActivityThread thread = new ActivityThread();//attach 方法 進(jìn)行 thread 的最初初始化操作 thread.attach(false);...Looper.loop();...}//main... }//ActivityThread② 子線程 : 子線程如果要?jiǎng)?chuàng)建 Handler , 需要先 調(diào)用 Looper.prepare() 方法 , 將線程轉(zhuǎn)為 Looper 線程 , 因?yàn)?創(chuàng)建 Handler 時(shí) , 會(huì)關(guān)聯(lián)線程的 Looper 對(duì)象 , 普通的子線程是沒(méi)有 Looper 對(duì)象的 , 調(diào)用 Looper.prepare() 方法即可為該線程創(chuàng)建 Looper 對(duì)象 , 該線程也就轉(zhuǎn)為了 Looper 線程 ;
public class handler {...//獲取 Looper 對(duì)象后 , 可以從 Looper 對(duì)象中獲取 MessageQueue//關(guān)聯(lián)后 , Handler 發(fā)送消息時(shí) , 才能將消息精準(zhǔn)的發(fā)送給final MessageQueue mQueue;//Handler 需要與線程的唯一 Looper 對(duì)象關(guān)聯(lián)final Looper mLooper; ...public Handler() {...mLooper = Looper.myLooper()if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");}...mQueue = mLooper.mQueue;...}... }2 . Handler 對(duì)象個(gè)數(shù) : 每個(gè) Looper 線程可以創(chuàng)建多個(gè) Handler , 只要該 Handler 與 Looper 和 MessageQueue 關(guān)聯(lián) , 就可以將 消息 ( Message ) 發(fā)送給 Looper 線程中的 MessageQueue 中 ; Looper 輪詢?cè)?消息隊(duì)列 ( MessageQueue ) , 將消息再次分發(fā)給對(duì)應(yīng)的 Handler 進(jìn)行處理 ;
IV . Looper ( 消息遍歷者 )
1 . Looper 線程 : 如果要將 Handler , Looper 機(jī)制引入到線程中 , 使某線程具有接收 Message ( 消息 ) , 執(zhí)行某項(xiàng)操作的功能 , 需要將該線程轉(zhuǎn)為 Looper 線程 ;
2 . Looper 線程可執(zhí)行的操作 : 一個(gè)線程如果被轉(zhuǎn)為 Looper 線程 , 那這個(gè)線程運(yùn)行后只能接收 Message 消息 , 執(zhí)行對(duì)應(yīng)的操作 , 運(yùn)行后永遠(yuǎn)卡在 loop 循環(huán)遍歷的 while (true) 循環(huán)中 , 使用 quit() 方法才能退出 ;
3 . Loop.prepare() 方法 : 該方法是將 普通子線程 轉(zhuǎn)為 Looper 線程最終要的方法 , 該方法的主要作用是 創(chuàng)建 Looper , 然后將 Looper 對(duì)象放入 ThreadLocal 對(duì)象中存儲(chǔ) ; 線程只有創(chuàng)建了 Looper 對(duì)象才能創(chuàng)建 Handler , 將該 Looper 對(duì)象及其中封裝的 MessageQueue 與 Handler 進(jìn)行關(guān)聯(lián) , Handler 才可以進(jìn)行消息的調(diào)度 ; 如果線程中沒(méi)有 Looper 對(duì)象 , 創(chuàng)建 Handler 會(huì)報(bào)運(yùn)行時(shí)異常 ;
public final class Looper {...// sThreadLocal.get() will return null unless you've called prepare().@UnsupportedAppUsagestatic final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();...private static void prepare(boolean quitAllowed) {if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper(quitAllowed));}... }4 . Loop.loop() 方法 : 一旦調(diào)用了該方法 , 就意味著該 Looper 線程進(jìn)入到了輪詢 MessageQueue 的階段 , 這是一個(gè)無(wú)限死循環(huán) , 調(diào)用了該方法后 , Handler 發(fā)送消息 , 線程才能處理對(duì)應(yīng)的業(yè)務(wù)邏輯 ;
調(diào)用 quit() 方法 , 可以終止該遍歷 MessageQueue 操作 ;
下面代碼刪除了大部分代碼 , 只留下 循環(huán)遍歷 和 調(diào)度 Message 信息給 Handler 進(jìn)行處理 ;
public static void loop() {final Looper me = myLooper();...final MessageQueue queue = me.mQueue;...for (;;) {Message msg = queue.next(); // 阻塞if (msg == null) {// 循環(huán)遍歷退出return;}...try {//調(diào)度 Message 信息給 Handler 進(jìn)行處理 msg.target.dispatchMessage(msg);...} ...} }V . Looper 子線程
1 . Looper 線程就是在普通線程的基礎(chǔ)是哪個(gè) , 加入了 Looper 用于消息調(diào)度 , 然后將消息轉(zhuǎn)發(fā)給 Handler 進(jìn)行處理 , 這樣就實(shí)現(xiàn)了 在其它線程中 , 將任務(wù)異步分配給該 Looper 線程 ;
2 . Android 中的主線程本身就是 Looper 線程 , 整個(gè) Looper 循環(huán)遍歷消息的過(guò)程由系統(tǒng)完成 , 用戶只需要自定義一個(gè) Handler 成員 , 即可在子線程中調(diào)用該 Handler 將消息發(fā)送到主線程 , 在主線程執(zhí)行相關(guān)操作 , 實(shí)現(xiàn)了將異步任務(wù)分配給主線程 , 這是子線程刷新 UI 的重要途徑 ;
3 . 普通子線程 轉(zhuǎn)為 Looper 子線程 流程 :
① 定義 Handler 成員變量 : 在線程 Thread 派生類中 , 定義 Handler 類型的成員變量 ;
② Looper 初始化 : 調(diào)用 Looper.prepare() 靜態(tài)方法 , 該方法的作用是創(chuàng)建 Looper 變量 , 存儲(chǔ)在了 ThreadLocal 中 , 將當(dāng)前普通線程轉(zhuǎn)為 Looper 線程 ;
③ 實(shí)例化 Handler 成員 : 一定要在 Looper.prepare() 之后實(shí)例化成員 , 因?yàn)槿绻谥皩?shí)例化 , Handler 與 Looper 無(wú)法產(chǎn)生關(guān)聯(lián) ;
④ 輪詢消息隊(duì)列 : 調(diào)用 Looper.loop() 方法 , 輪詢消息隊(duì)列 ( MessageQueue ) ;
4 . 實(shí)例化 Handler 成員時(shí)機(jī) :
① 實(shí)例化時(shí)機(jī) : 必須要在調(diào)用 Looper.prepare() 之后實(shí)例化才可以 , 因?yàn)閷?shí)例化 Handler 對(duì)象時(shí) , 會(huì)獲取當(dāng)前線程的 Looper , 如果為空 , 直接拋異常 ;
② Looper 對(duì)象創(chuàng)建 : Looper.prepare() 的作用就是創(chuàng)建 Looper 對(duì)象 , 將其放入 ThreadLocal 對(duì)象中存儲(chǔ) , 保證線程有且只有一個(gè) Looper 對(duì)象 ;
public class handler {...//獲取 Looper 對(duì)象后 , 可以從 Looper 對(duì)象中獲取 MessageQueue//關(guān)聯(lián)后 , Handler 發(fā)送消息時(shí) , 才能將消息精準(zhǔn)的發(fā)送給final MessageQueue mQueue;//Handler 需要與線程的唯一 Looper 對(duì)象關(guān)聯(lián)final Looper mLooper; ...public Handler() {...mLooper = Looper.myLooper()if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");}...mQueue = mLooper.mQueue;...}... }5 . 普通子線程 轉(zhuǎn)為 Looper 子線程 代碼示例 :
package kim.hsl.handler;import android.os.Handler; import android.os.Looper; import android.os.Message;import androidx.annotation.NonNull;/*** 將普通線程轉(zhuǎn)為 Looper 線程** 1. 定義 Handler 成員 ( 可以定義若干個(gè) )* 2. Looper.prepare()* 3. 實(shí)例化 Handler 成員* 4. Looper.loop()** @author hsl*/ public class LooperThread extends Thread {/*** 1. 定義時(shí)不要實(shí)例化* Handler 實(shí)例化需要關(guān)聯(lián) Looper 對(duì)象* Looper 對(duì)象在 Looper*/private Handler handler;@Overridepublic void run() {super.run();//2. 將線程轉(zhuǎn)為 Looper 線程//主要是創(chuàng)建 Looper 放入 ThreadLocal 對(duì)象中Looper.prepare();//3. 創(chuàng)建 Handler 必須在 Looper.prepare() 之后, 否則會(huì)崩潰handler = new Handler(){@Overridepublic void handleMessage(@NonNull Message msg) {super.handleMessage(msg);//TODO 處理 Handler 相關(guān)業(yè)務(wù)邏輯}};//4. Looper 開始輪詢 MessageQueue, 將消息調(diào)度給 Handler 處理Looper.loop();}public Handler getHandler() {return handler;}public void setHandler(Handler handler) {this.handler = handler;} }
VI . Handler 發(fā)送 消息 種類
Handler 既可以發(fā)送靜態(tài)的 消息 ( Message ) , 又可以發(fā)送動(dòng)態(tài)的 操作 ( Runnable ) ;
當(dāng) Handler 所在的 Looper 線程接收到 消息 ( Message ) 時(shí) , Looper 輪詢到該 消息 ( Message ) 后 , 執(zhí)行該消息對(duì)應(yīng)的業(yè)務(wù)邏輯 , 這些邏輯一般都是在 Handler 中提前定義好的 ;
當(dāng) Handler 所在的 Looper 線程接收到 操作 ( Runnable ) 時(shí) , Looper 輪詢到該 操作 ( Runnable ) 后 , 直接運(yùn)行該 Runnable 中的 run() 方法 ;
VII . Handler 機(jī)制總結(jié)
1 . Handler 機(jī)制運(yùn)行流程 : Message 通過(guò) Handler 發(fā)送給 Looper 線程的 MessageQueue , Looper 輪詢 MessageQueue 將 Message 交給 Handler 執(zhí)行 ;
2 . 線程異步調(diào)用 ( 作用 ) : 子線程刷新主線程 UI ( 子線程調(diào)用主線程 ) , 主線程調(diào)用子線程異步網(wǎng)絡(luò)操作 ( 主線程調(diào)用子線程 ) ;
3 . 子線程轉(zhuǎn) Looper 線程 : ① 定義Handler 成員 ( 可以多個(gè) ) , ② Loop.prepare() , ③ Handler 初始化 ( 必須在 prepare 之后 ) , ④ Looper.loop() ;
4 . 四組件關(guān)系 : 111線程 ?\Leftrightarrow? 111 Looper ?\Leftrightarrow? 111 MessageQueue ?\Leftrightarrow? nnn Handler ?\Leftrightarrow? mmm Message ;
總結(jié)
以上是生活随笔為你收集整理的【Android】Handler 机制 ( Handler | Message | Looper | MessageQueue )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【Netty】NIO 网络通信 Sele
- 下一篇: 【Netty】NIO 网络编程 聊天室案