Handler機(jī)制
Handler 主要是用于異步消息處理籍胯,類似于輔助類竟闪,他封裝了消息的投遞 處理的接口,通常用來(lái)處理耗時(shí)較長(zhǎng)的操作
handler中有四個(gè)重要的對(duì)象:
Looper 它的內(nèi)部包含了一個(gè)消息隊(duì)列,也就是Messagequeue 所有的handler發(fā)送的消息都會(huì)進(jìn)入這個(gè)消息隊(duì)列
Looper的loop方法 是一個(gè)死循環(huán)? 它不斷的從MessageQueue中來(lái)獲取消息 如果有消息就處理消息 沒(méi)有消息他就會(huì)進(jìn)去阻塞狀態(tài)
Meassagequeue 就是一個(gè)消息隊(duì)列 可以添加消息并處理消息
當(dāng)我們?cè)谥骶€程new一個(gè)Handler 的時(shí)候我們就可以使用主線程的Handler關(guān)聯(lián)到我們的looper和messagequeue當(dāng)我們難道數(shù)據(jù)以后我們用handlersendmesssage方法 用looper 這個(gè)循環(huán)去得到我們的數(shù)據(jù)
Activity的生命周期也是依賴handler的消息機(jī)制來(lái)進(jìn)行回調(diào)的 是在我們ActivityThread里handler 依靠 what 盡心分值 去進(jìn)行不同的回調(diào)方法杖狼,從而實(shí)現(xiàn)不同的Activity的生命周期炼蛤。handler 主要用于異步消息處理,Android提供給我們來(lái)更新UI的一套機(jī)制本刽,可以通過(guò)handler來(lái)發(fā)送消息鲸湃,也可以來(lái)接受并處理消息赠涮。
? 異步消息處理:? android 在設(shè)計(jì)時(shí)就分裝了這么一套機(jī)制,可以通過(guò)handler來(lái)發(fā)送消息暗挑,也可以接受并處理消息
如果不遵循這個(gè)機(jī)制就無(wú)法更新UI笋除,就會(huì)拋出異常。為什么要通過(guò)handler機(jī)制來(lái)跟新UI呢炸裆,因?yàn)榧僭O(shè)activity中有多個(gè)線程去更新ui ,并且沒(méi)有加鎖機(jī)制垃它,就會(huì)產(chǎn)生頁(yè)面亂,如果對(duì)ui操作進(jìn)行枷鎖機(jī)制的會(huì)性能會(huì)下降烹看,所以我們使用handler 保證消息處理的先后順序国拇。
由于Handler是運(yùn)行在主線程中(UI線程中),? 而且它的設(shè)計(jì)可以使它與子線程通過(guò)Message對(duì)象來(lái)傳遞數(shù)據(jù), 這個(gè)時(shí)候,Handler就承擔(dān)著接受子線程傳過(guò)來(lái)的(子線程用sedMessage()方法傳弟)Message對(duì)象惯殊,(里面包含數(shù)據(jù))? ,把這些消息放入主線程隊(duì)列中酱吝,配合主線程進(jìn)行更新UI。子線程對(duì)主線程發(fā)信息Message對(duì)象(Message包含的信息可以是int土思,object類型)盡可能使用Message.what來(lái)標(biāo)識(shí)信息务热,以便用不同的方式處理Message;
執(zhí)行流程: 子線程通過(guò)sendmessage發(fā)送message消息己儒,這個(gè)消息會(huì)被放入messageQueue隊(duì)列中崎岂,
隊(duì)列會(huì)以先進(jìn)先出的方式,被Looper抽取闪湾,looper抽取到信息冲甘,交由主線程的handler,handler通過(guò)handleMessage處理信息途样,之后更新ui江醇。
handler主要有
Message:消息,其中包含了消息ID何暇,消息處理對(duì)象以及處理的數(shù)據(jù)等嫁审,由MessageQueue統(tǒng)一列隊(duì),終由Handler處理赖晶。
Handler:處理者,負(fù)責(zé)Message的發(fā)送及處理辐烂。使用Handler時(shí)遏插,需要實(shí)現(xiàn)handleMessage(Message msg)方法來(lái)對(duì)特定的Message進(jìn)行處理,例如更新UI等纠修。
Handler類的主要作用:(有兩個(gè)主要作用)1)胳嘲、在工作線程中發(fā)送消息;2)扣草、在主線程中獲取了牛、并處理消息颜屠。
MessageQueue:消息隊(duì)列,用來(lái)存放Handler發(fā)送過(guò)來(lái)的消息鹰祸,
并按照FIFO規(guī)則執(zhí)行甫窟。當(dāng)然,存放Message并非實(shí)際意義的保存蛙婴,而是將Message串聯(lián)起來(lái)的粗井,等待Looper的抽取。
Looper:消息泵街图,不斷地從MessageQueue中抽取Message執(zhí)行浇衬。因此,一個(gè)MessageQueue需要一個(gè)Looper餐济。 默認(rèn)一個(gè)線程是不存在消息循環(huán)的耘擂,需要調(diào)用Looper.prepare來(lái)創(chuàng)建一個(gè)消息循環(huán),
調(diào)用Looper.loop來(lái)使消息循環(huán)起作用絮姆,當(dāng)調(diào)用完loop方法后循環(huán)開(kāi)始醉冤,從消息MessageQueue隊(duì)列中抽取消息,下一個(gè)由handler發(fā)送的message將會(huì)被這個(gè)handler的handleMessage處理滚朵。處理完成后調(diào)用Message.recycle將其放入Message pool中冤灾。
Thread:線程,負(fù)責(zé)調(diào)度整個(gè)消息循環(huán)辕近,即消息循環(huán)的執(zhí)行場(chǎng)所韵吨。
handler引起內(nèi)存泄漏的原因及解決方案
如果用戶在網(wǎng)絡(luò)請(qǐng)求過(guò)程中關(guān)閉了Activity,正常情況下移宅,Activity不再被使用归粉,在onDestory()方法中執(zhí)行GC檢查時(shí)就應(yīng)該被回收掉。
但由于這時(shí)線程尚未執(zhí)行完漏峰,而該線程持有Handler的引用(不然它怎么發(fā)消息給Handler糠悼?),
這個(gè)Handler又持有Activity的引用浅乔,就導(dǎo)致該Activity無(wú)法被回收倔喂,造成內(nèi)存泄漏,直到網(wǎng)絡(luò)請(qǐng)求結(jié)束(圖片下載完畢)靖苇。
如果你執(zhí)行了Handler的postDelayed()方法席噩,該方法會(huì)將你的Handler裝入一個(gè)Message,并把這條Message推到MessageQueue中贤壁,那么在你設(shè)定的delay到達(dá)之前悼枢,
會(huì)有一條MessageQueue -> Message -> Handler -> Activity的鏈,導(dǎo)致你的Activity被持有引用而無(wú)法被回收脾拆。
解決:靜態(tài)內(nèi)部類馒索,靜態(tài)內(nèi)部類不會(huì)被當(dāng)前這個(gè)類所引用莹妒,再使用弱引用,gc觸發(fā)時(shí)將handler中的activity回收绰上。
在關(guān)閉Activity的時(shí)候停掉你的后臺(tái)線程旨怠。線程停掉了,就相當(dāng)于切斷了Handler和外部連接的線渔期,Activity自然會(huì)在合適的時(shí)候被回收运吓。
如果你的Handler是被delay的Message持有了引用,那么使用相應(yīng)的Handler的removeCallbacks()方法疯趟,把消息對(duì)象從消息隊(duì)列移除就行了拘哨。