Handler是什么胶哲?
handler是線程間消息傳遞的橋梁症歇,主要用來發(fā)送消息和處理消息魏铅。
為什么需要做線程間的通信淮腾?
Android不能在主線程(UI線程 / ActivityThread)中做耗時(shí)操作糟需,而子線程不能更新UI,當(dāng)子線程需要更新UI時(shí)候就需要通過Handler切換到主線程中谷朝。
為什么子線程不能更新UI?
Android的UI控件是線程不安全的洲押,如果在多線程中訪問同一個(gè)控件,會(huì)讓控件處于一個(gè)不可知的狀態(tài)圆凰。
為何系統(tǒng)不對(duì)控件進(jìn)行加鎖呢杈帐?
加鎖機(jī)制會(huì)讓控件邏輯變得復(fù)雜,同時(shí)降低了控件的訪問效率送朱,加鎖會(huì)阻止某些線程的執(zhí)行娘荡。
Handler如何發(fā)送消息和處理消息?
-
Handler
負(fù)責(zé)Message的發(fā)送和處理,按照先進(jìn)先出執(zhí)行驶沼,內(nèi)部使用的是單鏈表結(jié)構(gòu)炮沐。
sendMessage( )發(fā)送消息去消息池,handleMessage( )進(jìn)行消息的處理回怜。 -
MessageQueue
負(fù)責(zé)管理和存儲(chǔ)由Handler發(fā)送過來的Message大年。讀取會(huì)自動(dòng)刪除消息,單鏈表維護(hù)玉雾,插入和刪除上有優(yōu)勢翔试。 -
Message
需要被傳遞的消息,分為硬件產(chǎn)生的消息和軟件產(chǎn)生的消息复旬。 -
Looper
Looper通過loop( )開啟無限循環(huán)垦缅,通過MessageQueue的next( )方法不斷獲取消息,一旦拿到消息就會(huì)分發(fā)給Handler進(jìn)行處理驹碍,否則會(huì)在next( )中阻塞壁涎。當(dāng)Looper( )的quit( ) 調(diào)用會(huì)導(dǎo)致MessageQueue中的quit( )調(diào)用凡恍,next( )返回null,loop退出怔球。
主線程創(chuàng)建的時(shí)候會(huì)創(chuàng)建一個(gè)Looper嚼酝,同時(shí)也會(huì)在Looper內(nèi)部創(chuàng)建一個(gè)消息隊(duì)列。而在創(chuàng)建Handler的時(shí)候取出當(dāng)前線程的Looper竟坛,并通過該Looper對(duì)象獲取消息隊(duì)列闽巩,然后Handler在子線程通過Message.enqueueMessage在消息隊(duì)列添加消息。Looper.loop( )開啟循環(huán)從隊(duì)列中獲取消息后通過dispatchMessage( )發(fā)送給Handler担汤,最終由handleMessage( )進(jìn)行處理涎跨。
一個(gè)線程可以有多個(gè)Handler?
一個(gè)線程只會(huì)有一個(gè)Looper和一個(gè)消息隊(duì)列漫试,但是可以有多個(gè)Handler( )六敬。
Looper的死循環(huán)為什么不會(huì)導(dǎo)致系統(tǒng)卡死?
主線程的主要方法是消息循環(huán)驾荣,是要維持主線程一直存活的外构,一旦消息循環(huán)退出也就意味這應(yīng)用退出。Looper.loop( )可能會(huì)引起線程的阻塞播掷,但只要他的消息循環(huán)沒有被阻塞可以一直處理消息就不會(huì)產(chǎn)生ANR审编。造成ANR的原因不是主線程阻塞,而是處理消息的消息循環(huán)阻塞歧匈,無法響應(yīng)用戶的操作垒酬,不能即時(shí)的更新UI。阻塞與程序無響應(yīng)沒有必然聯(lián)系件炉,雖然在沒有消息的時(shí)候消息循環(huán)會(huì)阻塞在MessageQueue的next( )中(此時(shí)主線程會(huì)釋放CPU資源進(jìn)入休眠狀態(tài))勘究,但是只要有新消息的產(chǎn)生可以立刻進(jìn)行處理是不會(huì)發(fā)生程序無響應(yīng)的。
可以在子線程中創(chuàng)建Handler嗎斟冕?
可以創(chuàng)建口糕,但是需要自己維護(hù)一個(gè)Looper,并且要在所有事情做完后調(diào)用quit( )來終止消息循環(huán)磕蛇,否則這個(gè)線程會(huì)一直處于等待(阻塞)狀態(tài)景描。主線程在創(chuàng)建的時(shí)候會(huì)自動(dòng)創(chuàng)建Looper,會(huì)自動(dòng)管理處理發(fā)送過來的消息。Loooer在那個(gè)線程創(chuàng)建秀撇,就綁定那個(gè)線程超棺,并且Handler是在他關(guān)聯(lián)的Looper對(duì)應(yīng)的線程中處理消息的。
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
Looper.loop();
}
});
Handler導(dǎo)致內(nèi)存泄漏呵燕?
1.handler允許我們發(fā)送延時(shí)消息postDelay( ) 棠绘,如果在延時(shí)期間用戶關(guān)閉了Activity,那么該Activity就會(huì)泄漏。因?yàn)镸essage會(huì)持有Handler弄唧,又因?yàn)镴ava的特性适肠,內(nèi)部類會(huì)持有外部類霍衫,這樣Activity就被Handler所持有候引,導(dǎo)致泄漏。
1-1.所以敦跌,將Handler定義為靜態(tài)內(nèi)部類澄干,在內(nèi)部持有外部Activity的弱引用,并且在Activity退出的時(shí)候移除所有消息柠傍。
2.手動(dòng)為一個(gè)子線程創(chuàng)建Looper麸俘,當(dāng)消息處理完畢后,不手動(dòng)退出的情況下會(huì)一直處于等待狀態(tài)惧笛,而以quit( )退出Looper后从媚,線程會(huì)立刻關(guān)閉。
Handler患整、Thread和HandlerThread的差別拜效?
handler實(shí)現(xiàn)了線程間的通信,thread是java進(jìn)程中執(zhí)行運(yùn)算的最小單位各谚,也是執(zhí)行處理機(jī)調(diào)度的基本單位紧憾。Android沒有對(duì)Java的Thread進(jìn)行封裝,而是提供了一個(gè)繼承自Thread的HandlerThread,內(nèi)部維護(hù)了一個(gè)Looper,這是Handler消息機(jī)制必不可少的昌渤,有了looper才能做到消息的發(fā)放和處理赴穗,如果不用HandlerThread就需要自行維護(hù)一個(gè)Looper。
Message創(chuàng)建方式膀息?
Message m = new Message();
Message m2 = Message.obtain();
Message m3 = mHandler.obtainMessage();
第一種方法是直接實(shí)例化一個(gè)Message對(duì)象般眉,后兩者直接從Android的消息池(單項(xiàng)鏈表,默認(rèn)消息池?cái)?shù)量為10)中獲取一個(gè)Message實(shí)例潜支,這樣可以避免多生成Message實(shí)例浪費(fèi)內(nèi)存甸赃。
消息池中Message的對(duì)象是通過recycle()放進(jìn)去的.在Looper的loop()方法的最后調(diào)用了Message對(duì)象的recycle()方法來回收這個(gè)Message對(duì)象,通過recycle()將這個(gè)Message對(duì)象的數(shù)據(jù)清空然后鏈接到消息池中(采用的頭插法)毁腿。
其他子線程更新UI的方法辑奈?
除了Handler還有
- runOnUiThread( )
new Thread(new Runnable() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
mDiv.setVisibility(View.GONE);
}
});
}
}).start();
- view.Post( )
mNickName.post(new Runnable() {
@Override
public void run() {
mNickName.setText("********");
}
});
- AsyncTask