簡(jiǎn)介
Handler用于線程間的通信诫钓,即異步消息的處理,比如子線程下載文件/圖片篙螟,完成后通知主線程UI更改等等菌湃。handler用于發(fā)送消息和處理消息劲蜻。當(dāng)子線程的handler發(fā)送消息時(shí)蒸矛,消息會(huì)被送往主線程的消息隊(duì)列中(MessageQuene),等待Loop提取消息給主線程的Hanler處理。
為什么要設(shè)置通過(guò)Handler來(lái)更新UI锻拘,不用行嗎绪杏?
android在設(shè)計(jì)的時(shí)候纯路,就已經(jīng)封裝了一套完善的消息創(chuàng)建、傳遞寞忿、處理機(jī)制驰唬,如果不遵循這種機(jī)制就會(huì)拋異常。而設(shè)置這樣機(jī)制最根本的問(wèn)題是解決多線程并發(fā)帶來(lái)的一些列問(wèn)題腔彰。比如叫编,一個(gè)UI中有多個(gè)線程同時(shí)對(duì)同一個(gè)控件進(jìn)行更改樣式的操作,那這個(gè)控件就會(huì)很混亂霹抛,無(wú)法控制搓逾。如果我們對(duì)所有更新UI的操作都做枷鎖處理,其性能也會(huì)大打折扣杯拐。為了解決這樣的問(wèn)題霞篡,handler就誕生了,這使得我們?cè)诟耈I的時(shí)候不需要關(guān)心多線程問(wèn)題端逼。通常情況下朗兵,UI更新必須在主線程中進(jìn)行的,當(dāng)子線程需要更新UI時(shí)顶滩,就需要通過(guò)Handler發(fā)送消息到主線程的消息隊(duì)列中排隊(duì)等待處理余掖。
子線程中更新UI的幾種方式:??
一、使用runOnUiThread方式:
二礁鲁、通過(guò)Handler.sendMessage更新UI
PS:為了避免內(nèi)存泄露盐欺,在ondestroy的時(shí)候加下面這句:
三赁豆、通過(guò)Handler.Post更改UI
四、通過(guò)view.post更改UI
子線程更改UI基本就是上面4中冗美,看看Handler的工作原理
Handler原理
在說(shuō)明原理前魔种,我們需要了解他的成員以及作用
Handler:發(fā)送 / 處理? 消息
Looper:消息封裝的載體,類(lèi)似于一個(gè)加工廠粉洼。
MessageQueue:存放眾多消息务嫡,在Looper內(nèi)部,類(lèi)似于紐帶漆改。
Message:消息心铃,類(lèi)似于工作的物品。
handler首先發(fā)送消息到Looper工廠里面的紐帶上挫剑,紐帶很長(zhǎng)去扣,在工廠里面有一個(gè)抓手(Looper.Loop())這個(gè)抓手負(fù)責(zé)不斷的從紐帶上提取物品(message),當(dāng)沒(méi)有物品時(shí),抓手就停止工作(阻塞)樊破,抓手抓到的東西在送往主線程的Handler去處理愉棱。
HandlerThread是什么
handlerThread會(huì)創(chuàng)建一個(gè)含有l(wèi)ooper的handler,避免空指針異常哲戚。
在子線程創(chuàng)建Handler
在上面的代碼中奔滑,handler都是在主線程創(chuàng)建的,下面試試在子線程創(chuàng)建hander顺少,并讓他往主線程發(fā)送消息朋其。
首先創(chuàng)建MyThread線程
我們?cè)谧泳€程穿件ThreadHandler,這是子線程的Handler脆炎,在run中讓子線程發(fā)送消息梅猿,在子線程中處理,ThreadHandler的處理就是把消息發(fā)送給主線程的handler秒裕。讓主線程去處理哈~下面的截圖是主線程的handler袱蚓。
子線程是一定不能更改UI嗎?
其實(shí)不是的几蜻,子線程子所以不能改UI喇潘,是因?yàn)锳ndroid在線程的方法里面采用checkThread進(jìn)行判斷是否是主線程,而這個(gè)方法是在ViewRootImpl中的梭稚,這個(gè)類(lèi)是在onResume里面才生成的颖低,因此,如果這個(gè)時(shí)候子線程在onCreate方法里面生成更新UI哨毁,而且沒(méi)有做阻塞枫甲,就是耗時(shí)多的操作,還是可以更新UI的扼褪。但是不推薦這么做想幻!