1.handler基本信息:
定義:一套 Android 消息傳遞機(jī)制。
作用:在多線程的應(yīng)用場(chǎng)景中,將工作線程中需更新UI的操作信息 傳遞到 UI主線程,從而實(shí)現(xiàn) 工作線程對(duì)UI的更新處理捉偏,最終實(shí)現(xiàn)異步消息的處理。
使用Handler的原因:將工作線程需操作UI的消息 傳遞到主線程呻疹,使得主線程可根據(jù)工作線程的需求 更新UI适贸,從而避免線程操作不安全的問(wèn)題戈钢。
消息(Message):
定義:線程間通訊的數(shù)據(jù)單元(即Handler接收&處理的消息對(duì)象)
作用:存儲(chǔ)需操作的通信信息
消息隊(duì)列(Message Queue):
定義:一種數(shù)據(jù)結(jié)構(gòu)(存儲(chǔ)特點(diǎn):先進(jìn)先出)
作用:存儲(chǔ)Handler發(fā)送過(guò)來(lái)的消息(Message)
處理者(handler):
定義:主線程與子線程的通信媒介 線程消息的主要處理者
作用:添加消息(Message)到消息隊(duì)列(message Queue)處理循環(huán)器(Looper)分派過(guò)來(lái)的消息(message)
循環(huán)器(Looper):
定義:消息隊(duì)列(Message Queue)與處理者(Handler)的通信媒介
作用:消息循環(huán),即消息獲取:循環(huán)取出消息隊(duì)列(Message Queue)的消息(message)消息分發(fā):將取出的消息(Message)發(fā)送給對(duì)應(yīng)的處理者(Handler)
2..Handler使用方式 因發(fā)送消息到消息隊(duì)列的方式不同而不同
共分為2種:使用Handler.sendMessage()惊奇、使用Handler.post()
2原理
通過(guò)handler.sendMessage這個(gè)方法互躬,把當(dāng)前的消息對(duì)象message傳入到handler中,通過(guò)handler中的messagequeue對(duì)象的引用(通過(guò)在handler的構(gòu)造函數(shù)中颂郎,用looper獲取到的)吼渡,把Message放入到MessageQueue中。在message存放的時(shí)候乓序,message對(duì)象的target屬性記錄了當(dāng)前的handler寺酪。message通過(guò)消息的執(zhí)行時(shí)間when,從小到大排列插入到消息鏈表中替劈。我們looper的loop方法中的for(死循環(huán))去查看當(dāng)前的MessageQueue鏈表中是否有需要執(zhí)行的Message寄雀。通過(guò)Message的when(消息的執(zhí)行時(shí)間判斷)和當(dāng)前的系統(tǒng)時(shí)間戳做對(duì)比,如果當(dāng)前的系統(tǒng)時(shí)間戳小于當(dāng)前messagequeue鏈表中的消息執(zhí)行時(shí)間陨献,當(dāng)前的執(zhí)行進(jìn)入等待狀態(tài)盒犹。(管道機(jī)制,nativepollonce)如果當(dāng)前的系統(tǒng)時(shí)間戳大于或等于當(dāng)前的MessageQueue鏈表中的消息執(zhí)行時(shí)間眨业,我們就把當(dāng)前的message從消息鏈表中刪除急膀,并且把該消息返回給Looper的loop方法中。在loop方法中獲取到message以后判斷message所對(duì)應(yīng)的target(也就是發(fā)送message的handler)是否存在坛猪,如果存在就調(diào)用target.dispathMessage方法把當(dāng)前的message
傳入脖阵,在dispathMessage方法中皂股,我們將調(diào)用handleMessage這個(gè)方法墅茉。把當(dāng)前取出的message傳出去。這樣在我們handler中重寫(xiě)的handleMessage就拿到了當(dāng)前處理的消息呜呐。
4.Handler機(jī)制的工作流程主要包括4個(gè)步驟:
(1).異步通信準(zhǔn)備:
具體描述:在主線程中創(chuàng)建:處理器對(duì)象(Looper)消息隊(duì)列 對(duì)象(Message Queue)Handler 對(duì)象
(2).消息發(fā)送
具體描述:工作線程通過(guò)Handler發(fā)送消息(Message)到消息隊(duì)列(Message Queue)中
(3).消息循環(huán)
具體描述:消息出隊(duì):Looper循環(huán)取出消息隊(duì)列(Message Queue)中的消息(Message)消息分發(fā):Looper將取出的消息(Message)發(fā)送給創(chuàng)建消息的處理著(Handler)
(4).消息處理
具體描述:處理者(Handler)接收處理器(Looper)發(fā)送過(guò)來(lái)的消息(Message)處理者(Handler)根據(jù)消息(Message)進(jìn)行UI操作
5.當(dāng)創(chuàng)建Handler對(duì)象時(shí)就斤,則通過(guò) 構(gòu)造方法 自動(dòng)關(guān)聯(lián)當(dāng)前線程的Looper對(duì)象 & 對(duì)應(yīng)的消息隊(duì)列對(duì)象(MessageQueue),從而 自動(dòng)綁定了 實(shí)現(xiàn)創(chuàng)建Handler對(duì)象操作的線程
創(chuàng)建主線程時(shí)蘑辑,會(huì)自動(dòng)調(diào)用ActivityThread的1個(gè)靜態(tài)的main()洋机;而main()內(nèi)則會(huì)調(diào)用Looper.prepareMainLooper()為主線程生成1個(gè)Looper對(duì)象,同時(shí)也會(huì)生成其對(duì)應(yīng)的MessageQueue對(duì)象
即 主線程的Looper對(duì)象自動(dòng)生成洋魂,不需手動(dòng)生成绷旗;而子線程的Looper對(duì)象則需手動(dòng)通過(guò)Looper.prepare()創(chuàng)建
6.在子線程若不手動(dòng)創(chuàng)建Looper對(duì)象 則無(wú)法生成Handler對(duì)象
根據(jù)Handler的作用(在主線程更新UI),故Handler實(shí)例的創(chuàng)建場(chǎng)景 主要在主線程
消息循環(huán)的操作 = 消息出隊(duì) + 分發(fā)給對(duì)應(yīng)的Handler實(shí)例
分發(fā)給對(duì)應(yīng)的Handler的過(guò)程:根據(jù)出隊(duì)消息的歸屬者通過(guò)dispatchMessage(msg)進(jìn)行分發(fā)副砍,最終回調(diào)復(fù)寫(xiě)的handleMessage(Message msg)衔肢,從而實(shí)現(xiàn) 消息處理 的操作
特別注意:在進(jìn)行消息分發(fā)時(shí)(dispatchMessage(msg)),會(huì)進(jìn)行1次發(fā)送方式的判斷:
若msg.callback屬性不為空豁翎,則代表使用了post(Runnable r)發(fā)送消息角骤,則直接回調(diào)Runnable對(duì)象里復(fù)寫(xiě)的run()
若msg.callback屬性為空,則代表使用了sendMessage(Message msg)發(fā)送消息心剥,則回調(diào)復(fù)寫(xiě)的handleMessage(msg)
7.線程安全就是多線程訪問(wèn)時(shí)邦尊,采用了加鎖機(jī)制背桐,當(dāng)一個(gè)線程訪問(wèn)該類(lèi)的某個(gè)數(shù)據(jù)時(shí),進(jìn)行保護(hù)蝉揍,其他線程不能進(jìn)行訪問(wèn)直到該線程讀取完链峭,其他線程才可使用。不會(huì)出現(xiàn)數(shù)據(jù)不一致或者數(shù)據(jù)污染疑苫。 線程不安全就是不提供數(shù)據(jù)訪問(wèn)保護(hù)熏版,有可能出現(xiàn)多個(gè)線程先后更改數(shù)據(jù)造成所得到的數(shù)據(jù)是臟數(shù)據(jù)。
8.ThreadLocal提供了線程內(nèi)存儲(chǔ)變量的能力捍掺,這些變量不同之處在于每一個(gè)線程讀取的變量是對(duì)應(yīng)的互相獨(dú)立的撼短。通過(guò)get和set方法就可以得到當(dāng)前線程對(duì)應(yīng)的值。
ThreadLocal的靜態(tài)內(nèi)部類(lèi)ThreadLocalMap為每個(gè)Thread都維護(hù)了一個(gè)數(shù)組table挺勿,ThreadLocal確定了一個(gè)數(shù)組下標(biāo)曲横,而這個(gè)下標(biāo)就是value存儲(chǔ)的對(duì)應(yīng)位置。不瓶。
ThreadLocal是解決線程安全問(wèn)題一個(gè)很好的思路禾嫉,它通過(guò)為每個(gè)線程提供一個(gè)獨(dú)立的變量副本解決了變量并發(fā)訪問(wèn)的沖突問(wèn)題。在很多情況下蚊丐,ThreadLocal比直接使用synchronized同步機(jī)制解決線程安全問(wèn)題更簡(jiǎn)單熙参,更方便,且結(jié)果程序擁有更高的并發(fā)性麦备。
在每個(gè)線程Thread內(nèi)部有一個(gè)ThreadLocal.ThreadLocalMap類(lèi)型的成員變量threadLocals孽椰,這個(gè)threadLocals就是用來(lái)存儲(chǔ)實(shí)際的變量副本的,鍵值為當(dāng)前ThreadLocal變量凛篙,value為變量副本(即T類(lèi)型的變量)黍匾。 初始時(shí),在Thread里面呛梆,threadLocals為空锐涯,當(dāng)通過(guò)ThreadLocal變量調(diào)用get()方法或者set()方法,就會(huì)對(duì)Thread類(lèi)中的threadLocals進(jìn)行初始化填物,并且以當(dāng)前ThreadLocal變量為鍵值纹腌,以ThreadLocal要保存的副本變量為value,存到threadLocals滞磺。 然后在當(dāng)前線程里面升薯,如果要使用副本變量,就可以通過(guò)get方法在threadLocals里面查找雁刷。
實(shí)際的通過(guò)ThreadLocal創(chuàng)建的副本是存儲(chǔ)在每個(gè)線程自己的threadLocals中的覆劈;
為何threadLocals的類(lèi)型ThreadLocalMap的鍵值為T(mén)hreadLocal對(duì)象,因?yàn)槊總€(gè)線程中可有多個(gè)threadLocal變量,就像上面代碼中的longLocal和stringLocal责语;
在進(jìn)行g(shù)et之前炮障,必須先set,否則會(huì)報(bào)空指針異常坤候;如果想在get之前不需要調(diào)用set就能正常訪問(wèn)的話胁赢,必須重寫(xiě)initialValue()方法。 因?yàn)樵谏厦娴拇a分析過(guò)程中白筹,我們發(fā)現(xiàn)如果沒(méi)有先set的話智末,即在map中查找不到對(duì)應(yīng)的存儲(chǔ),則會(huì)通過(guò)調(diào)用setInitialValue方法返回i徒河,而在setInitialValue方法中系馆,有一個(gè)語(yǔ)句是T value = initialValue(), 而默認(rèn)情況下顽照,initialValue方法返回的是null由蘑。
9.handler.post和handler.sendMessage本質(zhì)上是沒(méi)有區(qū)別的,都是發(fā)送一個(gè)消息到消息隊(duì)列中代兵,而且消息隊(duì)列和handler都是依賴(lài)于同一個(gè)線程的尼酿。
send方案發(fā)送消息(需要回調(diào)才能接收消息)
1、sendMessage(Message) 立即發(fā)送Message到消息隊(duì)列
2植影、sendMessageAtFrontOfQueue(Message) 立即發(fā)送Message到隊(duì)列裳擎,而且是放在隊(duì)列的最前面
3、sendMessageAtTime(Message,long) 設(shè)置時(shí)間思币,發(fā)送Message到隊(duì)列
4鹿响、sendMessageDelayed(Message,long) 延時(shí)若干毫秒后,發(fā)送Message到隊(duì)列
post方案 立即發(fā)送Message到消息隊(duì)列
1支救、post(Runnable) 立即發(fā)送Message到消息隊(duì)列
2抢野、postAtFrontOfQueue(Runnable) 立即發(fā)送Message到隊(duì)列拷淘,而且是放在隊(duì)列的最前面
3各墨、postAtTime(Runnable,long) 設(shè)置時(shí)間,發(fā)送Message到隊(duì)列
4启涯、postDelayed(Runnable,long) 在延時(shí)若干毫秒后贬堵,發(fā)送Message到隊(duì)列
10.handler機(jī)制中包含4個(gè)關(guān)鍵類(lèi)(下面對(duì)源碼的解析也是從這4個(gè)類(lèi)入手),Message(消息)结洼,MessageQueue(消息隊(duì)列)黎做,Looper(輪詢器),Handler(消息發(fā)送和接收并處理)松忍,簡(jiǎn)單一句話概括就是:handler負(fù)責(zé)發(fā)送message蒸殿,將其加入到MessageQueue中,Looper不間斷的從MessageQueue中取出消息,并發(fā)送給對(duì)應(yīng)的handler實(shí)例去處理.
11.主線程與子線程
主線程((Ui線程宏所,Main.thread):
定義:當(dāng)應(yīng)用程序第一次啟動(dòng)時(shí)酥艳,會(huì)同時(shí)開(kāi)啟1條主線程。
作用:處理與UI相關(guān)的事件(如更新操作等)爬骤。
子線程(工作線程):
定義:人為手動(dòng)開(kāi)啟的線程充石。
作用:執(zhí)行耗時(shí)操作(如網(wǎng)絡(luò)請(qǐng)求、數(shù)據(jù)加載等)