一、什么是Handler
由于Android的只允許在UI線程(主線程)中修改UI組件,為了解決其他線程無法改變組件屬性值而使用Handler類處理
作用:
- 在新啟動(dòng)的線程中發(fā)送消息
- 在主線程中獲取處理消息
二、Handler的使用
1.post(Runnable)
post方法用于handleMessage()的作用一樣處理數(shù)據(jù)更新UI,源碼如下,也是調(diào)用sendMessageDelayed方法,省略了很多創(chuàng)建Handler的代碼 (適用于處理單一情況)
/**
* Causes the Runnable r to be added to the message queue.
* The runnable will be run on the thread to which this handler is
* attached.
*
* @param r The Runnable that will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
2.sendMessage(Message)
sendMessage有多種發(fā)送消息的方式,有發(fā)送空數(shù)據(jù)和延遲兩個(gè)屬性,根據(jù)具體的情況選擇和合適的方式
而且能發(fā)送不同類型消息,在handlMessage中處理。(適用于多種情況)
三、Handler內(nèi)部機(jī)制
- Message:Hanler接收和處理的消息對(duì)象。
- MessageQueue:消息隊(duì)列,使用FIFO(先進(jìn)先出)的方式管理Message。創(chuàng)建Loop對(duì)象是,也會(huì)在構(gòu)造器中創(chuàng)建MessageQuene對(duì)象
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
- Looper:每個(gè)線程只能擁有一個(gè)Looper,Looper的主要作用是負(fù)責(zé)讀取MessageQueen的Message,讀到的Message發(fā)送給Handler來處理。
- Handler:發(fā)送和處理消息,Handler正常工作必須在當(dāng)前線程中擁有一個(gè)MessageQueen隊(duì)列和管理MessageQueen的Looper
- 在UI線程中已經(jīng)初始化一個(gè)Message和Looper,直接創(chuàng)建Handler即可以處理消息
- 新的線程中必須Looper.prepare();創(chuàng)建MessageQueen和Looper,然后 Looper.loop();方法啟動(dòng)
new Thread(new Runnable() {
@Override
public void run() {
try {
Looper.prepare();
sendHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO
}
};
Looper.loop();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
Looper.loop();的作用是通過死循環(huán)的方式不斷地從MessageQueen中讀取消息
四、Handler引起的內(nèi)存泄漏以及解決方案
原因:在java中非靜態(tài)內(nèi)部類和匿名內(nèi)部類都會(huì)隱式持有當(dāng)前類的外部引用,由于Handler是非靜態(tài)內(nèi)部類所以其持有當(dāng)前Activity的隱式引用,如果Handler沒有被釋放,其所持有的外部引用也就是Activity也不可能被釋放,因此造成內(nèi)存泄漏。比如Hander中延遲5min發(fā)送消息,在MessaageQueen中隊(duì)列中持有Hander引用,這隊(duì)列間接持有Activity引用
解決辦法:
- 使用靜態(tài)內(nèi)部類,對(duì)Activity進(jìn)行弱引用
private static class MyHandler extends Handler{
//持有弱引用HandlerActivity,GC回收時(shí)會(huì)被回收掉.
private final WeakReference<HandlerActivity> mActivty;
public MyHandler(HandlerActivity activity){
mActivty =new WeakReference<HandlerActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
HandlerActivity activity=mActivty.get();
super.handleMessage(msg);
if(activity!=null){
//執(zhí)行業(yè)務(wù)邏輯
}
}
}
private static final Runnable myRunnable = new Runnable() {
@Override
public void run() {
//執(zhí)行我們的業(yè)務(wù)邏輯
}
};
- 在onDestroy()中,四messageQueenqi清空
serHandler.removeCallbacksAndMessages(null);
五、如何使用Handler讓子線程與子線程之間進(jìn)行通信
1.創(chuàng)建兩個(gè)子線程,分別在子線程內(nèi)創(chuàng)建Hander對(duì)象
2.分別在子線程內(nèi)發(fā)送消息
- 因?yàn)長(zhǎng)ooper.loop()是阻塞線程的因此在loop()之前發(fā)送消息
- 如果構(gòu)造時(shí)不提供Looper類對(duì)象參數(shù),會(huì)獲取當(dāng)前線程的Looper對(duì)象