至尊寶是真真的愛著紫霞仙子。? -- 題記
先看下測試代碼:
從上圖可知mHandler是在onCreate的主線程執(zhí)行的;mInnerHandler是在子線程執(zhí)行的;
?1秀睛、從handler的源碼角度看看handler是如何執(zhí)行的
1.????從handler的構造器可知,每新建一個Handler對象會重新生成一個looper對象莲祸;通過mLooper會生成一個消息池MessageQueue蹂安;也就是說一個Handler對象對應一個Looper對象,一個Looper對應一個消息池锐帜;
1.1? ? 那么myLooper方法是如何生成Looper的呢田盈?
? ? ThreadLocal?源碼注釋中有很清楚的解釋:它是線程的局部變量,這些變量只能在這個線程內(nèi)被讀寫缴阎,在其他線程內(nèi)是無法訪問的允瞧。get方法? ?是ThreadLocal 里的一個方法,
?從當前線程獲取map,從map里獲取Looper瓷式;;
截下來看下getMap()方法是怎么獲取到ThreadLocalMap的
他是Thread線程里的一個方法语泽,這里說明了在哪個線程里創(chuàng)建的handler對象贸典,handlerMessage就在哪個線程;一個線程只有一個Looper踱卵、只有一個MessageQueen廊驼,只有一個只供當前線程使用的ThreadLocal ;
ThreadLocal 有get()方法惋砂,那么他也一定要set方法妒挎;
這回知道為什么在線程里new Handler對象要調(diào)用Looper.prepare()了吧;
2.為什么在OnCreate里西饵,沒有調(diào)用Looper.prepare 酝掩?
我們看下ActivityThread這個類
他這里已經(jīng)調(diào)用了,啟用的是主線程眷柔;這里還是是main方法期虾,Activity的OnCreate還沒有被調(diào)用,原因下次再說驯嘱;
截下來我們看下 Looper.loop()方法镶苞;
所以loop方法的調(diào)用肯定都是在一個方法的最后,因為這是一個死循環(huán)鞠评,執(zhí)行這個方法就不再執(zhí)行下邊的任何步驟了茂蚓;
當前線程的Looper從消息隊列讀取消息,當讀完所有消息時剃幌,進入睡眠聋涨,線程阻塞。線程往消息隊列發(fā)送消息负乡,并且往管道文件寫數(shù)據(jù)牛郑,線程即被喚醒,從管道文件讀取數(shù)據(jù)敬鬓,主線程被喚醒只是為了讀取消息淹朋,當消息讀取完畢,再次睡眠钉答。
那么他是怎么往消息隊列里添加消息的呢础芍?
通過????mHandler.sendEmptyMessage(1);這類的方法,通過mHandler.sendxxxxxMessage源碼我們可知道,他們最終調(diào)用的都是sendMessageAtTime方法
這里最終調(diào)用的是消息池的enqueueMessage方法数尿,將消息添加到隊列仑性,根據(jù)message對象的when的值將消息排隊,然后喚醒當前線程繼續(xù)輪詢右蹦;
Looper.loop()方法里的for死循環(huán)里將消息分發(fā)出去
msg.target.dispatchMessage中的target點進去其實就是Handler對象诊杆,它調(diào)用自己的HandleMessage方法將其回調(diào)出去
總結
if ( 從onCreate里new Handler){
????????在ActivityThread的main()方法中存入了Looper.prepareMainLooper();(這里已經(jīng)創(chuàng)建了Looper歼捐,messagequeue)
} else {
????????每次在新的線程創(chuàng)建Handler對象 需要調(diào)用Looper.prepare();邏輯執(zhí)行完還要調(diào)用Looper.loop();去啟動消息池的輪詢;
}
new Handler的時候Handler就已經(jīng)拿到了線程的Looper 晨汹。MessagQueue
handler發(fā)送消息:
把Handler保存到Message里豹储。
把Message保存到messageQueue里。
然后不斷地執(zhí)行獲取消息的方法:Looper.loop();去出message淘这,然后調(diào)用handler的dispatchMessage(msg),消息回調(diào)到當前handler的handleMessage里;