前言
在Android開發的多線程應用場景中,Handler機制十分常用
今天,我將手把手帶你深入分析Handler機制的源碼,希望你們會喜歡
目錄
示意圖
1. Handler 機制簡介
定義
一套Android消息傳遞機制
作用
在多線程的應用場景中,將工作線程中需更新UI的操作信息 傳遞到UI主線程,從而實現 工作線程對UI的更新處理,最終實現異步消息的處理
示意圖
為什么要用Handler消息傳遞機制
答:多個線程并發更新UI的同時 保證線程安全。具體描述如下
示意圖
總結
使用Handler的原因:將工作線程需操作UI的消息 傳遞 到主線程,使得主線程可根據工作線程的需求 更新UI,從而避免線程操作不安全的問題
2. 儲備知識
在閱讀Handler機制的源碼分析前,請務必了解Handler的一些儲備知識:相關概念、使用方式 & 工作原理
2.1 相關概念
關于Handler機制中的相關概念如下:
在下面的講解中,我將直接使用英文名講解,即Handler、Message、Message Queue、Looper,希望大家先熟悉相關概念
示意圖
2.2 使用方式
Handler使用方式 因發送消息到消息隊列的方式不同而不同,共分為2種:使用Handler.sendMessage()、使用Handler.post()
下面的源碼分析將依據使用步驟講解
若還不了解,請務必閱讀文章:Android:這是一份Handler消息傳遞機制 的使用教程
2.3 工作原理
理解Handler機制的工作原理,能很大程序幫助理解其源碼
具體請看文章:Android Handler:圖文解析 Handler通信機制 的工作原理
3. Handler機制的核心類
在源碼分析前,先來了解Handler機制中的核心類
3.1 類說明
Handler機制 中有3個重要的類:
處理器 類(Handler)
消息隊列 類(MessageQueue)
循環器 類(Looper)
3.2 類圖
示意圖
3.3 具體介紹
示意圖
4. 源碼分析
下面的源碼分析將根據Handler的使用步驟進行
Handler使用方式 因發送消息到消息隊列的方式不同而不同,共分為2種:使用Handler.sendMessage()、使用Handler.post()
若還不了解,請務必閱讀文章:Android:這是一份Handler消息傳遞機制 的使用教程
下面的源碼分析將依據上述2種使用方式進行
方式1:使用 Handler.sendMessage()
使用步驟
/**
? * 此處以 匿名內部類 的使用方式為例
? */// 步驟1:在主線程中 通過匿名內部類 創建Handler類對象privateHandler mhandler =newHandler(){// 通過復寫handlerMessage()從而確定更新UI的操作@OverridepublicvoidhandleMessage(Message msg){? ? ? ? ? ? ? ? ? ? ? ? ...// 需執行的UI操作}? ? ? ? ? ? };// 步驟2:創建消息對象Message msg = Message.obtain();// 實例化消息對象msg.what =1;// 消息標識msg.obj ="AA";// 消息內容存放// 步驟3:在工作線程中 通過Handler發送消息到消息隊列中// 多線程可采用AsyncTask、繼承Thread類、實現RunnablemHandler.sendMessage(msg);// 步驟4:開啟工作線程(同時啟動了Handler)// 多線程可采用AsyncTask、繼承Thread類、實現Runnable
源碼分析
下面,我將根據上述每個步驟進行源碼分析
步驟1:在主線程中 通過匿名內部類 創建Handler類對象
/**
? * 具體使用
? */privateHandler mhandler =newHandler(){// 通過復寫handlerMessage()從而確定更新UI的操作@OverridepublicvoidhandleMessage(Message msg){? ? ? ? ? ? ? ? ...// 需執行的UI操作}? ? };/**
? * 源碼分析:Handler的構造方法
? * 作用:初始化Handler對象 & 綁定線程
? * 注:
? *? a. Handler需綁定 線程才能使用;綁定后,Handler的消息處理會在綁定的線程中執行
? *? b. 綁定方式 = 先指定Looper對象,從而綁定了 Looper對象所綁定的線程(因為Looper對象本已綁定了對應線程)
? *? c. 即:指定了Handler對象的 Looper對象 = 綁定到了Looper對象所在的線程
? */publicHandler(){this(null,false);// ->>分析1}/**
? * 分析1:this(null, false) = Handler(null,false)
? */publicHandler(Callback callback,booleanasync){? ? ? ? ? ? ...// 僅貼出關鍵代碼// 1. 指定Looper對象mLooper = Looper.myLooper();if(mLooper ==null) {thrownewRuntimeException("Can't create handler inside thread that has not called Looper.prepare()");? ? ? ? ? ? ? ? }// Looper.myLooper()作用:獲取當前線程的Looper對象;若線程無Looper對象則拋出異常// 即 :若線程中無創建Looper對象,則也無法創建Handler對象// 故 若需在子線程中創建Handler對象,則需先創建Looper對象// 注:可通過Loop.getMainLooper()可以獲得當前進程的主線程的Looper對象// 2. 綁定消息隊列對象(MessageQueue)mQueue = mLooper.mQueue;// 獲取該Looper對象中保存的消息隊列對象(MessageQueue)// 至此,保證了handler對象 關聯上 Looper對象中MessageQueue}
從上面可看出:
當創建Handler對象時,則通過 構造方法 自動關聯當前線程的Looper對象 & 對應的消息隊列對象(MessageQueue),從而 自動綁定了 實現創建Handler對象操作的線程
那么,當前線程的Looper對象 & 對應的消息隊列對象(MessageQueue)是什么時候創建的呢?
在上述使用步驟中,并無 創建Looper對象 & 對應的消息隊列對象(MessageQueue)這1步
步驟1前的隱式操作1:創建循環器對象(Looper) & 消息隊列對象(MessageQueue)
步驟介紹
示意圖
源碼分析
/**
? * 源碼分析1:Looper.prepare()
? * 作用:為當前線程(子線程) 創建1個循環器對象(Looper),同時也生成了1個消息隊列對象(MessageQueue)
? * 注:需在子線程中手動調用該方法
? */publicstaticfinalvoidprepare(){if(sThreadLocal.get() != null) {thrownewRuntimeException("Only one Looper may be created per thread");? ? ? ? }// 1. 判斷sThreadLocal是否為null,否則拋出異常//即 Looper.prepare()方法不能被調用兩次 = 1個線程中只能對應1個Looper實例// 注:sThreadLocal = 1個ThreadLocal對象,用于存儲線程的變量sThreadLocal.set(newLooper(true));// 2. 若為初次Looper.prepare(),則創建Looper對象 & 存放在ThreadLocal變量中// 注:Looper對象是存放在Thread線程里的// 源碼分析Looper的構造方法->>分析a}/**
? ? * 分析a:Looper的構造方法
? ? **/privateLooper(boolean quitAllowed){? ? ? ? ? ? mQueue =newMessageQueue(quitAllowed);// 1. 創建1個消息隊列對象(MessageQueue)// 即 當創建1個Looper實例時,會自動創建一個與之配對的消息隊列對象(MessageQueue)mRun =true;? ? ? ? ? ? mThread = Thread.currentThread();? ? ? ? }/**
? * 源碼分析2:Looper.prepareMainLooper()
? * 作用:為 主線程(UI線程) 創建1個循環器對象(Looper),同時也生成了1個消息隊列對象(MessageQueue)
? * 注:該方法在主線程(UI線程)創建時自動調用,即 主線程的Looper對象自動生成,不需手動生成
? */// 在Android應用進程啟動時,會默認創建1個主線程(ActivityThread,也叫UI線程)// 創建時,會自動調用ActivityThread的1個靜態的main()方法 = 應用程序的入口// main()內則會調用Looper.prepareMainLooper()為主線程生成1個Looper對象/**
? ? ? ? * 源碼分析:main()
? ? ? ? **/publicstaticvoidmain(String[] args){? ? ? ? ? ? ...// 僅貼出關鍵代碼Looper.prepareMainLooper();// 1. 為主線程創建1個Looper對象,同時生成1個消息隊列對象(MessageQueue)// 方法邏輯類似Looper.prepare()// 注:prepare():為子線程中創建1個Looper對象ActivityThread thread =newActivityThread();// 2. 創建主線程Looper.loop();// 3. 自動開啟 消息循環 ->>下面將詳細分析}
總結:
創建主線程時,會自動調用ActivityThread的1個靜態的main();而main()內則會調用Looper.prepareMainLooper()為主線程生成1個Looper對象,同時也會生成其對應的MessageQueue對象
即 主線程的Looper對象自動生成,不需手動生成;而子線程的Looper對象則需手動通過Looper.prepare()創建
在子線程若不手動創建Looper對象 則無法生成Handler對象
根據Handler的作用(在主線程更新UI),故Handler實例的創建場景 主要在主線程
生成Looper&MessageQueue對象后,則會自動進入消息循環:Looper.loop(),即又是另外一個隱式操作。
步驟1前的隱式操作2:消息循環
此處主要分析的是Looper類中的loop()方法
/**
? * 源碼分析: Looper.loop()
? * 作用:消息循環,即從消息隊列中獲取消息、分發消息到Handler
? * 特別注意:
? *? ? ? a. 主線程的消息循環不允許退出,即無限循環
? *? ? ? b. 子線程的消息循環允許退出:調用消息隊列MessageQueue的quit()
? */publicstaticvoidloop(){? ? ? ? ? ? ? ? ...// 僅貼出關鍵代碼// 1. 獲取當前Looper的消息隊列finalLooper me = myLooper();if(me ==null) {thrownewRuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");? ? ? ? ? ? }// myLooper()作用:返回sThreadLocal存儲的Looper實例;若me為null 則拋出異常// 即loop()執行前必須執行prepare(),從而創建1個Looper實例finalMessageQueue queue = me.mQueue;// 獲取Looper實例中的消息隊列對象(MessageQueue)// 2. 消息循環(通過for循環)for(;;) {// 2.1 從消息隊列中取出消息Message msg = queue.next();if(msg ==null) {return;? ? ? ? ? ? }// next():取出消息隊列里的消息// 若取出的消息為空,則線程阻塞// ->> 分析1 // 2.2 派發消息到對應的Handlermsg.target.dispatchMessage(msg);// 把消息Message派發給消息對象msg的target屬性// target屬性實際是1個handler對象// ->>分析2// 3. 釋放消息占據的資源msg.recycle();? ? ? ? }}/**
? * 分析1:queue.next()
? * 定義:屬于消息隊列類(MessageQueue)中的方法
? * 作用:出隊消息,即從 消息隊列中 移出該消息
? */Messagenext(){? ? ? ? ...// 僅貼出關鍵代碼// 該參數用于確定消息隊列中是否還有消息// 從而決定消息隊列應處于出隊消息狀態 or 等待狀態intnextPollTimeoutMillis =0;for(;;) {if(nextPollTimeoutMillis !=0) {? ? ? ? ? ? ? ? Binder.flushPendingCommands();? ? ? ? ? ? }// nativePollOnce方法在native層,若是nextPollTimeoutMillis為-1,此時消息隊列處于等待狀態 nativePollOnce(ptr, nextPollTimeoutMillis);synchronized(this) {finallongnow = SystemClock.uptimeMillis();? ? ? ? ? ? Message prevMsg =null;? ? ? ? ? ? Message msg = mMessages;// 出隊消息,即 從消息隊列中取出消息:按創建Message對象的時間順序if(msg !=null) {if(now < msg.when) {? ? ? ? ? ? ? ? ? ? nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);? ? ? ? ? ? ? ? }else{// 取出了消息mBlocked =false;if(prevMsg !=null) {? ? ? ? ? ? ? ? ? ? ? ? prevMsg.next = msg.next;? ? ? ? ? ? ? ? ? ? }else{? ? ? ? ? ? ? ? ? ? ? ? mMessages = msg.next;? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? msg.next =null;if(DEBUG) Log.v(TAG,"Returning message: "+ msg);? ? ? ? ? ? ? ? ? ? msg.markInUse();returnmsg;? ? ? ? ? ? ? ? }? ? ? ? ? ? }else{// 若 消息隊列中已無消息,則將nextPollTimeoutMillis參數設為-1// 下次循環時,消息隊列則處于等待狀態nextPollTimeoutMillis = -1;? ? ? ? ? ? }? ? ? ? ? ? ......? ? ? ? }? ? ? ? ? .....? ? ? }}// 回到分析原處/**
? * 分析2:dispatchMessage(msg)
? * 定義:屬于處理者類(Handler)中的方法
? * 作用:派發消息到對應的Handler實例 & 根據傳入的msg作出對應的操作
? */publicvoiddispatchMessage(Message msg){// 1. 若msg.callback屬性不為空,則代表使用了post(Runnable r)發送消息// 則執行handleCallback(msg),即回調Runnable對象里復寫的run()// 上述結論會在講解使用“post(Runnable r)”方式時講解if(msg.callback !=null) {? ? ? ? ? ? handleCallback(msg);? ? ? ? }else{if(mCallback !=null) {if(mCallback.handleMessage(msg)) {return;? ? ? ? ? ? ? ? }? ? ? ? ? ? }// 2. 若msg.callback屬性為空,則代表使用了sendMessage(Message msg)發送消息(即此處需討論的)// 則執行handleMessage(msg),即回調復寫的handleMessage(msg) ->> 分析3handleMessage(msg);? ? ? ? }? ? }/**
? * 分析3:handleMessage(msg)
? * 注:該方法 = 空方法,在創建Handler實例時復寫 = 自定義消息處理方式
? **/publicvoidhandleMessage(Message msg){? ? ? ? ? ? ...// 創建Handler實例時復寫}
總結:
消息循環的操作 = 消息出隊 + 分發給對應的Handler實例
分發給對應的Handler的過程:根據出隊消息的歸屬者通過dispatchMessage(msg)進行分發,最終回調復寫的handleMessage(Message msg),從而實現 消息處理 的操作
特別注意:在進行消息分發時(dispatchMessage(msg)),會進行1次發送方式的判斷:
若msg.callback屬性不為空,則代表使用了post(Runnable r)發送消息,則直接回調Runnable對象里復寫的run()
若msg.callback屬性為空,則代表使用了sendMessage(Message msg)發送消息,則回調復寫的handleMessage(msg)
至此,關于步驟1的源碼分析講解完畢。總結如下
示意圖
步驟2:創建消息對象
/**
? * 具體使用
? */Message msg = Message.obtain();// 實例化消息對象msg.what =1;// 消息標識msg.obj ="AA";// 消息內容存放/**
? * 源碼分析:Message.obtain()
? * 作用:創建消息對象
? * 注:創建Message對象可用關鍵字new 或 Message.obtain()
? */publicstaticMessageobtain(){// Message內部維護了1個Message池,用于Message消息對象的復用// 使用obtain()則是直接從池內獲取synchronized(sPoolSync) {if(sPool !=null) {? ? ? ? ? ? ? ? Message m = sPool;? ? ? ? ? ? ? ? sPool = m.next;? ? ? ? ? ? ? ? m.next =null;? ? ? ? ? ? ? ? m.flags =0;// clear in-use flagsPoolSize--;returnm;? ? ? ? ? ? }// 建議:使用obtain()”創建“消息對象,避免每次都使用new重新分配內存}// 若池內無消息對象可復用,則還是用關鍵字new創建returnnewMessage();? ? }
總結
示意圖
步驟3:在工作線程中 發送消息到消息隊列中
多線程的實現方式:AsyncTask、繼承Thread類、實現Runnable
/**
? * 具體使用
? */mHandler.sendMessage(msg);/**
? * 源碼分析:mHandler.sendMessage(msg)
? * 定義:屬于處理器類(Handler)的方法
? * 作用:將消息 發送 到消息隊列中(Message ->> MessageQueue)
? */publicfinalbooleansendMessage(Message msg){returnsendMessageDelayed(msg,0);// ->>分析1}/**
? ? ? ? ? * 分析1:sendMessageDelayed(msg, 0)
? ? ? ? ? **/publicfinalbooleansendMessageDelayed(Message msg,longdelayMillis){if(delayMillis <0) {? ? ? ? ? ? ? ? ? ? delayMillis =0;? ? ? ? ? ? ? ? }returnsendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);// ->> 分析2}/**
? ? ? ? ? * 分析2:sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)
? ? ? ? ? **/publicbooleansendMessageAtTime(Message msg,longuptimeMillis){// 1. 獲取對應的消息隊列對象(MessageQueue)MessageQueue queue = mQueue;// 2. 調用了enqueueMessage方法 ->>分析3returnenqueueMessage(queue, msg, uptimeMillis);? ? ? ? ? ? ? ? }/**
? ? ? ? ? * 分析3:enqueueMessage(queue, msg, uptimeMillis)
? ? ? ? ? **/privatebooleanenqueueMessage(MessageQueue queue, Message msg,longuptimeMillis){// 1. 將msg.target賦值為this// 即 :把 當前的Handler實例對象作為msg的target屬性msg.target =this;// 請回憶起上面說的Looper的loop()中消息循環時,會從消息隊列中取出每個消息msg,然后執行msg.target.dispatchMessage(msg)去處理消息// 實際上則是將該消息派發給對應的Handler實例? ? ? ? // 2. 調用消息隊列的enqueueMessage()// 即:Handler發送的消息,最終是保存到消息隊列->>分析4returnqueue.enqueueMessage(msg, uptimeMillis);? ? ? ? }/**
? ? ? ? ? * 分析4:queue.enqueueMessage(msg, uptimeMillis)
? ? ? ? ? * 定義:屬于消息隊列類(MessageQueue)的方法
? ? ? ? ? * 作用:入隊,即 將消息 根據時間 放入到消息隊列中(Message ->> MessageQueue)
? ? ? ? ? * 采用單鏈表實現:提高插入消息、刪除消息的效率
? ? ? ? ? */booleanenqueueMessage(Message msg,longwhen){? ? ? ? ? ? ? ? ...// 僅貼出關鍵代碼synchronized(this) {? ? ? ? ? ? ? ? ? ? msg.markInUse();? ? ? ? ? ? ? ? ? ? msg.when = when;? ? ? ? ? ? ? ? ? ? Message p = mMessages;booleanneedWake;// 判斷消息隊列里有無消息// a. 若無,則將當前插入的消息 作為隊頭 & 若此時消息隊列處于等待狀態,則喚醒if(p ==null|| when ==0|| when < p.when) {? ? ? ? ? ? ? ? ? ? ? ? ? ? msg.next = p;? ? ? ? ? ? ? ? ? ? ? ? ? ? mMessages = msg;? ? ? ? ? ? ? ? ? ? ? ? ? ? needWake = mBlocked;? ? ? ? ? ? ? ? ? ? ? ? }else{? ? ? ? ? ? ? ? ? ? ? ? ? ? needWake = mBlocked && p.target ==null&& msg.isAsynchronous();? ? ? ? ? ? ? ? ? ? ? ? ? ? Message prev;// b. 判斷消息隊列里有消息,則根據 消息(Message)創建的時間 插入到隊列中for(;;) {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? prev = p;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? p = p.next;if(p ==null|| when < p.when) {break;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }if(needWake && p.isAsynchronous()) {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? needWake =false;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ? msg.next = p;? ? ? ? ? ? ? ? ? ? ? ? ? ? prev.next = msg;? ? ? ? ? ? ? ? ? ? ? ? }if(needWake) {? ? ? ? ? ? ? ? ? ? ? ? ? ? nativeWake(mPtr);? ? ? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? }returntrue;? ? ? ? ? ? }// 之后,隨著Looper對象的無限消息循環// 不斷從消息隊列中取出Handler發送的消息 & 分發到對應Handler// 最終回調Handler.handleMessage()處理消息
總結
Handler發送消息的本質 = 為該消息定義target屬性(即本身實例對象) & 將消息入隊到綁定線程的消息隊列中。具體如下:
示意圖
至此,關于使用Handler.sendMessage()的源碼解析完畢
總結
根據操作步驟的源碼分析總結
示意圖
工作流程總結
下面,將順著文章:工作流程再理一次
示意圖
示意圖
方式2:使用 Handler.post()
使用步驟
// 步驟1:在主線程中創建Handler實例privateHandler mhandler =newmHandler();// 步驟2:在工作線程中 發送消息到消息隊列中 & 指定操作UI內容// 需傳入1個Runnable對象mHandler.post(newRunnable() {@Overridepublicvoidrun(){? ? ? ? ? ? ? ? ...// 需執行的UI操作 }? ? });// 步驟3:開啟工作線程(同時啟動了Handler)// 多線程可采用AsyncTask、繼承Thread類、實現Runnable
源碼分析
下面,我將根據上述每個步驟進行源碼分析
實際上,該方式與方式1中的Handler.sendMessage()工作原理相同、源碼分析類似,下面將主要講解不同之處
步驟1:在主線程中創建Handler實例
/**
? * 具體使用
? */privateHandler mhandler =newHandler();// 與方式1的使用不同:此處無復寫Handler.handleMessage()/**
? * 源碼分析:Handler的構造方法
? * 作用:
? *? ? a. 在此之前,主線程創建時隱式創建Looper對象、MessageQueue對象
? *? ? b. 初始化Handler對象、綁定線程 & 進入消息循環
? * 此處的源碼分析類似方式1,此處不作過多描述
? */
步驟2:在工作線程中 發送消息到消息隊列中
/**
? * 具體使用
? * 需傳入1個Runnable對象、復寫run()從而指定UI操作
? */mHandler.post(newRunnable() {? ? ? ? ? ? @Overridepublicvoidrun() {? ? ? ? ? ? ? ? ...// 需執行的UI操作 }? ? });/**
? * 源碼分析:Handler.post(Runnable r)
? * 定義:屬于處理者類(Handler)中的方法
? * 作用:定義UI操作、將Runnable對象封裝成消息對象 & 發送 到消息隊列中(Message ->> MessageQueue)
? * 注:
? *? ? a. 相比sendMessage(),post()最大的不同在于,更新的UI操作可直接在重寫的run()中定義
? *? ? b. 實際上,Runnable并無創建新線程,而是發送 消息 到消息隊列中
? */publicfinal booleanpost(Runnable r){returnsendMessageDelayed(getPostMessage(r),0);// getPostMessage(r) 的源碼分析->>分析1// sendMessageDelayed()的源碼分析 ->>分析2}/**
? ? ? ? ? ? ? * 分析1:getPostMessage(r)
? ? ? ? ? ? ? * 作用:將傳入的Runable對象封裝成1個消息對象
? ? ? ? ? ? ? **/privatestaticMessagegetPostMessage(Runnable r){// 1. 創建1個消息對象(Message)Message m = Message.obtain();// 注:創建Message對象可用關鍵字new 或 Message.obtain()// 建議:使用Message.obtain()創建,// 原因:因為Message內部維護了1個Message池,用于Message的復用,使用obtain()直接從池內獲取,從而避免使用new重新分配內存// 2. 將 Runable對象 賦值給消息對象(message)的callback屬性m.callback = r;// 3. 返回該消息對象returnm;? ? ? ? ? ? ? ? ? ? }// 回到調用原處/**
? ? ? ? ? ? ? * 分析2:sendMessageDelayed(msg, 0)
? ? ? ? ? ? ? * 作用:實際上,從此處開始,則類似方式1 = 將消息入隊到消息隊列,
? ? ? ? ? ? ? * 即 最終是調用MessageQueue.enqueueMessage()
? ? ? ? ? ? ? **/publicfinal booleansendMessageDelayed(Message msg,longdelayMillis){if(delayMillis <0) {? ? ? ? ? ? ? ? ? ? ? ? delayMillis =0;? ? ? ? ? ? ? ? ? ? }returnsendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);// 請看分析3}/**
? ? ? ? ? ? ? * 分析3:sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)
? ? ? ? ? ? ? **/publicbooleansendMessageAtTime(Message msg,longuptimeMillis){// 1. 獲取對應的消息隊列對象(MessageQueue)MessageQueuequeue= mQueue;// 2. 調用了enqueueMessage方法 ->>分析3returnenqueueMessage(queue, msg, uptimeMillis);? ? ? ? ? ? ? ? ? ? }/**
? ? ? ? ? ? ? * 分析4:enqueueMessage(queue, msg, uptimeMillis)
? ? ? ? ? ? ? **/privatebooleanenqueueMessage(MessageQueuequeue, Message msg,longuptimeMillis){// 1. 將msg.target賦值為this// 即 :把 當前的Handler實例對象作為msg的target屬性msg.target =this;// 請回憶起上面說的Looper的loop()中消息循環時,會從消息隊列中取出每個消息msg,然后執行msg.target.dispatchMessage(msg)去處理消息// 實際上則是將該消息派發給對應的Handler實例? ? ? ? // 2. 調用消息隊列的enqueueMessage()// 即:Handler發送的消息,最終是保存到消息隊列returnqueue.enqueueMessage(msg, uptimeMillis);? ? ? ? ? ? }// 注:實際上從分析2開始,源碼 與 sendMessage(Message msg)發送方式相同
從上面的分析可看出:
消息對象的創建 = 內部 根據Runnable對象而封裝
發送到消息隊列的邏輯 = 方式1中sendMessage(Message msg)
下面,我們重新回到步驟1前的隱式操作2:消息循環,即Looper類中的loop()方法
/**
? * 源碼分析: Looper.loop()
? * 作用:消息循環,即從消息隊列中獲取消息、分發消息到Handler
? * 特別注意:
? *? ? ? a. 主線程的消息循環不允許退出,即無限循環
? *? ? ? b. 子線程的消息循環允許退出:調用消息隊列MessageQueue的quit()
? */publicstaticvoidloop(){? ? ? ? ? ? ? ? ...// 僅貼出關鍵代碼// 1. 獲取當前Looper的消息隊列finalLooper me = myLooper();if(me ==null) {thrownewRuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");? ? ? ? ? ? }// myLooper()作用:返回sThreadLocal存儲的Looper實例;若me為null 則拋出異常// 即loop()執行前必須執行prepare(),從而創建1個Looper實例finalMessageQueue queue = me.mQueue;// 獲取Looper實例中的消息隊列對象(MessageQueue)// 2. 消息循環(通過for循環)for(;;) {// 2.1 從消息隊列中取出消息Message msg = queue.next();if(msg ==null) {return;? ? ? ? ? ? }// next():取出消息隊列里的消息// 若取出的消息為空,則線程阻塞// 2.2 派發消息到對應的Handlermsg.target.dispatchMessage(msg);// 把消息Message派發給消息對象msg的target屬性// target屬性實際是1個handler對象// ->>分析1// 3. 釋放消息占據的資源msg.recycle();? ? ? ? }}/**
? * 分析1:dispatchMessage(msg)
? * 定義:屬于處理者類(Handler)中的方法
? * 作用:派發消息到對應的Handler實例 & 根據傳入的msg作出對應的操作
? */publicvoiddispatchMessage(Message msg){// 1. 若msg.callback屬性不為空,則代表使用了post(Runnable r)發送消息(即此處需討論的)// 則執行handleCallback(msg),即回調Runnable對象里復寫的run()->> 分析2if(msg.callback !=null) {? ? ? ? ? ? handleCallback(msg);? ? ? ? }else{if(mCallback !=null) {if(mCallback.handleMessage(msg)) {return;? ? ? ? ? ? ? ? }? ? ? ? ? ? }// 2. 若msg.callback屬性為空,則代表使用了sendMessage(Message msg)發送消息(即此處需討論的)// 則執行handleMessage(msg),即回調復寫的handleMessage(msg) handleMessage(msg);? ? ? ? }? ? }/**
? ? * 分析2:handleCallback(msg)
? ? **/privatestaticvoidhandleCallback(Message message){? ? ? ? message.callback.run();//? Message對象的callback屬性 = 傳入的Runnable對象// 即回調Runnable對象里復寫的run()}
至此,你應該明白使用Handler.post()的工作流程:與方式1(Handler.sendMessage())類似,區別在于:
不需外部創建消息對象,而是內部根據傳入的Runnable對象 封裝消息對象
回調的消息處理方法是:復寫Runnable對象的run()
二者的具體異同如下:
示意圖
至此,關于使用Handler.post()的源碼解析完畢
總結
根據操作步驟的源碼分析總結
示意圖
工作流程總結
下面,將順著文章:工作流程再理一次
示意圖
示意圖
至此,關于Handler機制的源碼全部分析完畢。
5. 總結
本文詳細分析了Handler機制的源碼,文字總結 & 流程圖如下:
示意圖
示意圖
示意圖
示意圖
作者:Carson_Ho
鏈接:http://www.lxweimin.com/p/b4d745c7ff7a
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。