Android 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析
| 1、Handler的由來 |
當程序第一次啟動的時候,Android會同時啟動一條主線程( Main Thread)來負責處理與UI相關的事件,我們叫做UI線程。
Android的UI操作并不是線程安全的(出于性能優(yōu)化考慮),意味著如果多個線程并發(fā)操作UI線程,可能導致線程安全問題。
為了解決Android應用多線程問題—Android平臺只允許UI線程修改Activity里的UI組建,就會導致新啟動的線程無法改變界面組建的屬性值。
簡單的說:當主線程隊列處理一個消息超過5秒,android 就會拋出一個 ANR(無響應)的異常,所以,我們需要把一些要處理比較長的消息,放在一個單獨線程里面處理,把處理以后的結果,返回給主線程運行,就需要用的Handler來進行線程建的通信。
| 2、Handler的作用 |
2.1 讓線程延時執(zhí)行
主要用到的兩個方法:
-
final boolean postAtTime(Runnable r, long uptimeMillis)
-
final boolean postDelayed(Runnable r, long delayMillis)
2.2 讓任務在其他線程中執(zhí)行并返回結果
分為兩個步驟:
-
在新啟動的線程中發(fā)送消息
使用Handler對象的sendMessage()方法或者SendEmptyMessage()方法發(fā)送消息。
-
在主線程中獲取處理消息
重寫Handler類中處理消息的方法(void handleMessage(Message msg)),當新啟動的線程發(fā)送消息時,消息發(fā)送到與之關聯(lián)的MessageQueue。而Hanlder不斷地從MessageQueue中獲取并處理消息。
| 3、Handler更新UI線程一般使用 |
- 首先要進行Handler 申明,復寫handleMessage方法( 放在主線程中)
- 子線程發(fā)送Message給ui線程表示自己任務已經(jīng)執(zhí)行完成,主線程可以做相應的操作了。
| 4、Handler原理分析 |
4.1 Handler的構造函數(shù)
① public Handler()?
② public Handler(Callbackcallback)?
③ public Handler(Looperlooper)?
④ public Handler(Looperlooper, Callbackcallback)
- 第①個和第②個構造函數(shù)都沒有傳遞Looper,這兩個構造函數(shù)都將通過調(diào)用Looper.myLooper()獲取當前線程綁定的Looper對象,然后將該Looper對象保存到名為mLooper的成員字段中。 ?
下面來看①②個函數(shù)源碼:?
我們看到暗紅色的重點部分:
通過Looper.myLooper()獲取了當前線程保存的Looper實例,又通過這個Looper實例獲取了其中保存的MessageQueue(消息隊列)。每個Handler 對應一個Looper對象,產(chǎn)生一個MessageQueue?
- 第③個和第④個構造函數(shù)傳遞了Looper對象,這兩個構造函數(shù)會將該Looper保存到名為mLooper的成員字段中。?
下面來看③④個函數(shù)源碼:
- 第②個和第④個構造函數(shù)還傳遞了Callback對象,Callback是Handler中的內(nèi)部接口,需要實現(xiàn)其內(nèi)部的handleMessage方法,Callback代碼如下:
Handler.Callback是用來處理Message的一種手段,如果沒有傳遞該參數(shù),那么就應該重寫Handler的handleMessage方法,也就是說為了使得Handler能夠處理Message,我們有兩種辦法:?
?
1. 向Hanlder的構造函數(shù)傳入一個Handler.Callback對象,并實現(xiàn)Handler.Callback的handleMessage方法 ?
?
2. 無需向Hanlder的構造函數(shù)傳入Handler.Callback對象,但是需要重寫Handler本身的handleMessage方法 ?
?
也就是說無論哪種方式,我們都得通過某種方式實現(xiàn)handleMessage方法,這點與Java中對Thread的設計有異曲同工之處。
4.2 Handle發(fā)送消息的幾個方法源碼
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">sendMessage</span>(Message msg){<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> sendMessageDelayed(msg, <span class="hljs-number" style="color:#06666;box-sizing: border-box;">0</span>);}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul> <code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">sendEmptyMessageDelayed</span>(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">int</span> what, <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">long</span> delayMillis) {Message msg = Message.obtain();msg.what = what;<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> sendMessageDelayed(msg, delayMillis);}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul> <code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">sendMessageDelayed</span>(Message msg, <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">long</span> delayMillis){<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (delayMillis < <span class="hljs-number" style="color:#06666;box-sizing: border-box;">0</span>) {delayMillis = <span class="hljs-number" style="color:#06666;box-sizing: border-box;">0</span>;}<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul> <code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">sendMessageAtTime</span>(Message msg, <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">long</span> uptimeMillis) {MessageQueue queue = mQueue;<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (queue == <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) {RuntimeException e = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> RuntimeException(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span> + <span class="hljs-string" style="color:#0880;box-sizing: border-box;">" sendMessageAtTime() called with no mQueue"</span>);Log.w(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"Looper"</span>, e.getMessage(), e);<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">false</span>;}<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> enqueueMessage(queue, msg, uptimeMillis);}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>我們可以看出他們最后都調(diào)用了sendMessageAtTime(),然后返回了enqueueMessage方法,下面看一下此方法源碼:
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color:#06666;box-sizing: border-box;">626</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">enqueueMessage</span>(MessageQueue queue, Message msg, <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">long</span> uptimeMillis) {<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//把當前的handler作為msg的target屬性</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">627</span> msg.target = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>; <span class="hljs-number" style="color:#06666;box-sizing: border-box;">628</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (mAsynchronous) { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">629</span> msg.setAsynchronous(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">true</span>); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">630</span> } <span class="hljs-number" style="color:#06666;box-sizing: border-box;">631</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> queue.enqueueMessage(msg, uptimeMillis); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">632</span> }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>在該方法中有兩件事需要注意:
msg.target = this
該代碼將Message的target綁定為當前的Handler
?
變量queue表示的是Handler所綁定的消息隊列MessageQueue,通過調(diào)用queue.enqueueMessage(msg, uptimeMillis)我們將Message放入到消息隊列中。
過下圖可以看到完整的方法調(diào)用順序:
| 5、Looper原理分析 |
我們一般在主線程申明Handler,有時我們需要繼承Thread類實現(xiàn)自己的線程功能,當我們在里面申明Handler的時候會報錯。其原因是主線程中已經(jīng)實現(xiàn)了兩個重要的Looper方法,下面看一看ActivityThread.java中main方法的源碼:
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">main</span>(String[] args) {<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//......省略</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5205</span> Looper.prepareMainLooper();<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//></span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5206</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5207</span> ActivityThread thread = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> ActivityThread(); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5208</span> thread.attach(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">false</span>); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5209</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5210</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (sMainThreadHandler == <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5211</span> sMainThreadHandler = thread.getHandler(); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5212</span> } <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5213</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5214</span> AsyncTask.init(); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5215</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5216</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">false</span>) { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5217</span> Looper.myLooper().setMessageLogging(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5218</span> LogPrinter(Log.DEBUG, <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"ActivityThread"</span>)); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5219</span> } <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5220</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5221</span> Looper.loop();<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//></span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5222</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5223</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> RuntimeException(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"Main thread loop unexpectedly exited"</span>); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5224</span> } <span class="hljs-number" style="color:#06666;box-sizing: border-box;">5225</span>}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>5.1 首先看prepare()方法
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color:#06666;box-sizing: border-box;">70</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">prepare</span>() { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">71</span> prepare(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">true</span>); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">72</span> } <span class="hljs-number" style="color:#06666;box-sizing: border-box;">73</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">74</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">prepare</span>(boolean quitAllowed) {<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//證了一個線程中只有一個Looper實例</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">75</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (sThreadLocal.<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">get</span>() != <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">76</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> RuntimeException(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"Only one Looper may be created per thread"</span>); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">77</span> } <span class="hljs-number" style="color:#06666;box-sizing: border-box;">78</span> sThreadLocal.<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">set</span>(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> Looper(quitAllowed)); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">79</span> }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>該方法會調(diào)用Looper構造函數(shù)同時實例化出MessageQueue和當前thread.
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color:#06666;box-sizing: border-box;">186</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> <span class="hljs-title" style="box-sizing: border-box;">Looper</span>(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">boolean</span> quitAllowed) { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">187</span> mQueue = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> MessageQueue(quitAllowed); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">188</span> mThread = Thread.currentThread(); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">189</span> } <span class="hljs-number" style="color:#06666;box-sizing: border-box;">182</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> MessageQueue <span class="hljs-title" style="box-sizing: border-box;">myQueue</span>() { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">183</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> myLooper().mQueue; <span class="hljs-number" style="color:#06666;box-sizing: border-box;">184</span> } </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>prepare()方法中通過ThreadLocal對象實現(xiàn)Looper實例與線程的綁定。
5.2 loop()方法
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color:#06666;box-sizing: border-box;">109</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">loop</span>() { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">110</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">final</span> Looper me = myLooper(); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">111</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (me == <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">112</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> RuntimeException(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"No Looper; Looper.prepare() wasn't called on this thread."</span>); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">113</span> } <span class="hljs-number" style="color:#06666;box-sizing: border-box;">114</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">final</span> MessageQueue queue = me.mQueue; <span class="hljs-number" style="color:#06666;box-sizing: border-box;">115</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">118</span> Binder.clearCallingIdentity(); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">119</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">long</span> ident = Binder.clearCallingIdentity(); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">120</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">121</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">for</span> (;;) { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">122</span> Message msg = queue.next(); <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// might block</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">123</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (msg == <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">124</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">125</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span>; <span class="hljs-number" style="color:#06666;box-sizing: border-box;">126</span> } <span class="hljs-number" style="color:#06666;box-sizing: border-box;">127</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">129</span> Printer logging = me.mLogging; <span class="hljs-number" style="color:#06666;box-sizing: border-box;">130</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (logging != <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">131</span> logging.println(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">">>>>> Dispatching to "</span> + msg.target + <span class="hljs-string" style="color:#0880;box-sizing: border-box;">" "</span> + <span class="hljs-number" style="color:#06666;box-sizing: border-box;">132</span> msg.callback + <span class="hljs-string" style="color:#0880;box-sizing: border-box;">": "</span> + msg.what); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">133</span> } <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//重點****</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">135</span> msg.target.dispatchMessage(msg); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">136</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">137</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (logging != <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">138</span> logging.println(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"<<<<< Finished to "</span> + msg.target + <span class="hljs-string" style="color:#0880;box-sizing: border-box;">" "</span> + msg.callback); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">139</span> } <span class="hljs-number" style="color:#06666;box-sizing: border-box;">140</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">142</span> <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// identity of the thread wasn't corrupted.</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">143</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">long</span> newIdent = Binder.clearCallingIdentity(); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">144</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (ident != newIdent) { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">145</span> Log.wtf(TAG, <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"Thread identity changed from 0x"</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">146</span> + Long.toHexString(ident) + <span class="hljs-string" style="color:#0880;box-sizing: border-box;">" to 0x"</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">147</span> + Long.toHexString(newIdent) + <span class="hljs-string" style="color:#0880;box-sizing: border-box;">" while dispatching to "</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">148</span> + msg.target.getClass().getName() + <span class="hljs-string" style="color:#0880;box-sizing: border-box;">" "</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">149</span> + msg.callback + <span class="hljs-string" style="color:#0880;box-sizing: border-box;">" what="</span> + msg.what); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">150</span> } <span class="hljs-number" style="color:#06666;box-sizing: border-box;">151</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">152</span> msg.recycleUnchecked(); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">153</span> } <span class="hljs-number" style="color:#06666;box-sizing: border-box;">154</span> }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li></ul>首先looper對象不能為空,就是說loop()方法調(diào)用必須在prepare()方法的后面。
Looper一直在不斷的從消息隊列中通過MessageQueue的next方法獲取Message,然后通過代碼msg.target.dispatchMessage(msg)讓該msg所綁定的Handler(Message.target)執(zhí)行dispatchMessage方法以實現(xiàn)對Message的處理。
Handler的dispatchMessage的源碼如下:
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color:#06666;box-sizing: border-box;">93</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">dispatchMessage</span>(Message msg) { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">94</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (msg.callback != <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">95</span> handleCallback(msg); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">96</span> } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">else</span> { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">97</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (mCallback != <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">98</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (mCallback.handleMessage(msg)) { <span class="hljs-number" style="color:#06666;box-sizing: border-box;">99</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span>; <span class="hljs-number" style="color:#06666;box-sizing: border-box;">100</span> } <span class="hljs-number" style="color:#06666;box-sizing: border-box;">101</span> } <span class="hljs-number" style="color:#06666;box-sizing: border-box;">102</span> handleMessage(msg); <span class="hljs-number" style="color:#06666;box-sizing: border-box;">103</span> } <span class="hljs-number" style="color:#06666;box-sizing: border-box;">104</span> }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>我們可以看到Handler提供了三種途徑處理Message,而且處理有前后優(yōu)先級之分:首先嘗試讓postXXX中傳遞的Runnable執(zhí)行,其次嘗試讓Handler構造函數(shù)中傳入的Callback的handleMessage方法處理,最后才是讓Handler自身的handleMessage方法處理Message。
| 6、如何在子線程中使用Handler |
Handler本質(zhì)是從當前的線程中獲取到Looper來監(jiān)聽和操作MessageQueue,當其他線程執(zhí)行完成后回調(diào)當前線程。
子線程需要先prepare()才能獲取到Looper的,是因為在子線程只是一個普通的線程,其ThreadLoacl中沒有設置過Looper,所以會拋出異常,而在Looper的prepare()方法中sThreadLocal.set(new Looper())是設置了Looper的。
6.1 實例代碼
定義一個類實現(xiàn)Runnable接口或繼承Thread類(一般不繼承)。
<code class="hljs axapta has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">class</span> <span class="hljs-title" style="color:#66066;box-sizing: border-box;">Rub</span> <span class="hljs-inheritance" style="box-sizing: border-box;"><span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">implements</span></span> <span class="hljs-title" style="color:#66066;box-sizing: border-box;">Runnable</span> {</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> Handler myHandler; <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 實現(xiàn)Runnable接口的線程體 </span>@Override <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> run() { <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">/*①、調(diào)用Looper的prepare()方法為當前線程創(chuàng)建Looper對象并,創(chuàng)建Looper對象時,它的構造器會自動的創(chuàng)建相對應的MessageQueue*/</span>Looper.prepare(); <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">/*.②、創(chuàng)建Handler子類的實例,重寫HandleMessage()方法,該方法處理除當前線程以外線程的消息*/</span>myHandler = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> Handler() { @Override <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> handleMessage(Message msg) { String ms = <span class="hljs-string" style="color:#0880;box-sizing: border-box;">""</span>; <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (msg.what == <span class="hljs-number" style="color:#06666;box-sizing: border-box;">0x777</span>) { } } }; <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//③、調(diào)用Looper的loop()方法來啟動Looper讓消息隊列轉動起來</span>Looper.loop(); }}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li></ul>注意分成三步:
1.調(diào)用Looper的prepare()方法為當前線程創(chuàng)建Looper對象,創(chuàng)建Looper對象時,它的構造器會創(chuàng)建與之配套的MessageQueue。
2.有了Looper之后,創(chuàng)建Handler子類實例,重寫HanderMessage()方法,該方法負責處理來自于其他線程的消息。
3.調(diào)用Looper的looper()方法啟動Looper。
然后使用這個handler實例在任何其他線程中發(fā)送消息,最終處理消息的代碼都會在你創(chuàng)建Handler實例的線程中運行。
| 7、總結 |
Handler:?
發(fā)送消息,它能把消息發(fā)送給Looper管理的MessageQueue。?
處理消息,并負責處理Looper分給它的消息。?
Message:?
Handler接收和處理的消息對象。?
Looper:?
每個線程只有一個Looper,它負責管理對應的MessageQueue,會不斷地從MessageQueue取出消息,并將消息分給對應的Hanlder處理。 ?
?
主線程中,系統(tǒng)已經(jīng)初始化了一個Looper對象,因此可以直接創(chuàng)建Handler即可,就可以通過Handler來發(fā)送消息、處理消息。 程序自己啟動的子線程,程序必須自己創(chuàng)建一個Looper對象,并啟動它,調(diào)用Looper.prepare()方法。
prapare()方法:保證每個線程最多只有一個Looper對象。
looper()方法:啟動Looper,使用一個死循環(huán)不斷取出MessageQueue中的消息,并將取出的消息分給對應的Handler進行處理。
MessageQueue:由Looper負責管理,它采用先進先出的方式來管理Message。
Handler的構造方法,會首先得到當前線程中保存的Looper實例,進而與Looper實例中的MessageQueue想關聯(lián)。 ?
?
Handler的sendMessage方法,會給msg的target賦值為handler自身,然后加入MessageQueue中。
原文地址: http://blog.csdn.net/amazing7/article/details/51424038
總結
以上是生活随笔為你收集整理的Android 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android6.0源码分析—— Zyg
- 下一篇: Android异步任务机制之AsycTa