原理:
handler機(jī)制中包含4個(gè)關(guān)鍵類(下面對(duì)源碼的解析也是從這4個(gè)類入手)猫妙,Message(消息)歇终,MessageQueue(消息隊(duì)列)卤橄,Looper(輪詢器)乳附,Handler(消息發(fā)送和接收并處理)都毒,簡(jiǎn)單一句話概括就是:handler負(fù)責(zé)發(fā)送message色罚,將其加入到MessageQueue中,Looper不間斷的從MessageQueue中取出消息账劲,并發(fā)送給對(duì)應(yīng)的handler實(shí)例去處理戳护。
源碼理解:
我們經(jīng)常的使用handler是這樣的:
1、進(jìn)去源碼發(fā)現(xiàn)Hander是包含有Looper瀑焦,MessageQueue兩個(gè)比較重要的類腌且,handler 構(gòu)造器,調(diào)用下面的方法:
獲取looper對(duì)象:Looper.myLooper(); 進(jìn)去可以看到 返回了榛瓮,sThreadLocal.get();這個(gè)是什么玩意铺董?ThreadLocal,他是一個(gè)容器禀晓,里面封裝了一個(gè)map精续,以當(dāng)前線程的ThreadLocal作為key,以你要存的值作為value粹懒,我們這里value就是looper對(duì)象重付,這個(gè)容器是專門用來(lái)保存線程所特有的變量的,起到了線程間隔離的作用凫乖,如果有人想知道堪夭,我專門開一篇博客來(lái)講愕把。至于looper是怎么初始化的,客官莫急森爽,下面會(huì)講。
mQueue = mLooper.mQueue;拿到消息隊(duì)列嚣镜,這是一個(gè)鏈表結(jié)構(gòu)爬迟,注:一個(gè)線程對(duì)應(yīng)一個(gè)looper,一個(gè)looper同樣也只有一個(gè)queue菊匿;
callback這個(gè)是handler里面的一個(gè)接口付呕,在消息分發(fā)的時(shí)候會(huì)講到,默認(rèn)是null跌捆,mAsynchronous這個(gè)參數(shù)表示消息是否是異步消息徽职,默認(rèn)是false
2、再來(lái)看sendMessage佩厚,發(fā)送消息姆钉,:sendMessage ——> sendMessageDelayed ——>sendMessageAtTime
重點(diǎn):為什么msg要保存handler的引用呢?
我們都知道抄瓦,handler機(jī)制消息處理潮瓶,哪一個(gè)handler實(shí)例發(fā)出的消息,那么那一個(gè)handler就負(fù)責(zé)處理這個(gè)消息钙姊,這里的msg.target = this; 作用就在這毯辅,用來(lái)記住誰(shuí)將msg發(fā)出來(lái),等到處理的時(shí)候誰(shuí)就來(lái)處理煞额。
mMessages是即將要處理的message思恐,when越小,越要被有先處理膊毁。
3胀莹、重點(diǎn)又來(lái)了! Looper媚媒!
我們還是回到handler 初始化的時(shí)候嗜逻,我們是怎么獲取looper的,我們先看一個(gè)圖:
看上面的方法缭召,我們獲取Looper是從sThreadLocal獲取的栈顷。那我們就想它是何時(shí)set進(jìn)去的呢?我們想用looper嵌巷,就必須先prepare萄凤。
Looper是怎么初始化的呢,app中的通信搪哪,UI的刷新靡努,都需要依賴handler,那么,我們就猜想惑朦,Looper在app啟動(dòng)的時(shí)候就已經(jīng)開始創(chuàng)建并初始化了兽泄,那么我們?nèi)ピ创a中找 ActivityThread main()方法?
在主線程啟動(dòng)的時(shí)候就已經(jīng)啟動(dòng)了Looper并調(diào)用了,prepareMainLooper()和loop();接著去looper里面看看:
三個(gè)方法漾月,prepareMainLooper()其實(shí)內(nèi)部調(diào)用了prepare(false);這個(gè)boolean參數(shù)是什么意思呢病梢,意識(shí)就是不允許messageQueue退出,這個(gè)參數(shù)會(huì)在構(gòu)建Queue的時(shí)候傳遞進(jìn)去梁肿,因?yàn)橹骶€程的消息隊(duì)列只有在應(yīng)用退出的時(shí)候才允許退出蜓陌,否則······沒(méi)有否則,消息機(jī)制都沒(méi)了吩蔑,還怎么玩钮热!
prepare()方法創(chuàng)建了一個(gè)looper,但是looper并沒(méi)有啟動(dòng)烛芬,啟動(dòng)的方法是下面的loop();loop()有一個(gè)for(隧期;;),死循環(huán)蛀骇,里面做的工作就是一直取消息厌秒,并處理,然后recycleUnchecked()復(fù)用擅憔。這個(gè)時(shí)候looper就啟動(dòng)起來(lái)了鸵闪,只要你的應(yīng)用還在運(yùn)行,他就會(huì)一直在暑诸。looper拿到消息后會(huì)通過(guò)msg.target.dispatchMessage(msg); 將消息發(fā)出來(lái)給handler處理蚌讼,這里的msg.target不就是我們發(fā)消息的時(shí)候初始化的handler嗎?
判斷msg.callback是不是null个榕,如果不是篡石,那么就給這個(gè)callback處理,這個(gè)callback是message中的一個(gè)Runnable西采;Message.obtain()其實(shí)是有其他參數(shù)的方法的凰萨,其中有一個(gè)是obtain(Handler h, Runnable callback);如果你用了這個(gè)械馆,那么消息就會(huì)在你實(shí)現(xiàn)的Runnable中接收到處理的回調(diào)胖眷;
第二個(gè)是判斷handler內(nèi)部的callback是不是null,如果不是null霹崎,就讓他去處理珊搀,這里的Callback可不是Runnable了尾菇,他是一個(gè)interface境析,里面定義了一個(gè)handleMessage(Message msg);方法囚枪,這個(gè)怎么實(shí)現(xiàn)呢?handler類里同樣有Handler(Callback callback)構(gòu)造方法
最后才輪到handler類里的方法handleMessage來(lái)處理消息。也就是我們?cè)陂_始寫的那個(gè)簡(jiǎn)單的handler使用方法谒臼。