基本要素
- Message:消息的表示
- MessageQueue:消息隊(duì)列
- Looper:消息循環(huán),用于從消息隊(duì)列中取出消息
- Handler:消息處理
Handler的使用
- 初始化
為了使用Handler,必須初始化。
- 在主線程中,已經(jīng)預(yù)先初始化了,所以可以直接使用Handler.
- 而在自己創(chuàng)建的線程中,需要首先調(diào)用Looper.prepare();方法用來(lái)初始化MessageQueue和實(shí)例化Looper并設(shè)置Looper作為T(mén)hreadLocal的值,然后調(diào)用Looper.loop();方法進(jìn)行消息的循環(huán)和處理。
- 或者在構(gòu)造時(shí)使用已經(jīng)初始化的Looper,這樣的話,消息的處理依然是在Looper初始化時(shí)所在的線程。
擴(kuò)展Handler或者實(shí)現(xiàn)Handler.Callback接口作為Handler的構(gòu)造參數(shù),并實(shí)現(xiàn)handleMessage方法。實(shí)例化Handler子類時(shí),應(yīng)該在prepare和loop之間進(jìn)行。
獲得Handler對(duì)象實(shí)例,調(diào)用方法發(fā)送消息到消息隊(duì)列。消息可以是Runnable或Message類型,分別是使用post和send方法。
HandlerThread的使用
HandlerThread thread = new HandlerThread("thread name" );
thread.start (); // 要把線程啟動(dòng)
Handler handler = new Handler(thread.getLooper ()) {
// 實(shí)現(xiàn)handleMessage方法
}
因?yàn)镠andlerThread的run方法中,已經(jīng)調(diào)用Looper的prepare和loop方法,這個(gè)線程已經(jīng)在等待消息了。
Handler的構(gòu)造函數(shù)中,使用了上面線程的Looper,因此,發(fā)送給Handler的消息會(huì)放到上面線程的Queue中,且在上面線程中執(zhí)行。
post和sendMessage
post發(fā)送的Runnable最終被封裝為Message,其中Runnable作為Message的callback域的值。
然后當(dāng)Looper的消息循環(huán)收到消息時(shí),根據(jù)Message的target域中的值,會(huì)調(diào)用對(duì)應(yīng)Handler的dispatchMessage方法。
從方法中可以看到,如果Message的callback不為空(也就是使用post發(fā)送),那么直接調(diào)用Runnable的run方法,也就是說(shuō),在Looper所在的線程中同步處理。
否則,則在handleMessage方法中處理。默認(rèn)的handleMessage方法為空。
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r)
{
Message m = Message.obtain();
m.callback = r;
return m;
}
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
}
else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
Handler可能引起的內(nèi)存泄漏和解決方案
首先,Looper的prepare方法會(huì)設(shè)置Looper到ThreadLocal中,而ThreadLocal變量作為L(zhǎng)ooper的static變量,又因?yàn)镸essage的target字段中包含Handler的引用,而Message被放入消息隊(duì)列,所以導(dǎo)致Handler的生命周期比Activity長(zhǎng)。
如果Handler在Activity作為內(nèi)部類實(shí)現(xiàn),那么就會(huì)保存一個(gè)Activity的引用?;蛘呦㈥?duì)列中包含尚未處理的Message,當(dāng)Activity銷(xiāo)毀后,導(dǎo)致Activity不能被垃圾回收。
解決辦法:
- Handler作為靜態(tài)類或外部類實(shí)現(xiàn)
- Activity作為參數(shù)傳遞給Handler的構(gòu)造器
- Handler內(nèi)部使用軟引用或弱引用來(lái)保存Activity。
- 在handleMessage或run方法中使用Activity時(shí),應(yīng)該判斷它是否為空。
- 另外,在Handler的post參數(shù)Runnable,也不應(yīng)該使用內(nèi)部類。
另外,當(dāng)Activity銷(xiāo)毀時(shí),還在消息隊(duì)列中排隊(duì)的任務(wù)應(yīng)該被取消掉,否則Activity還是不能被垃圾回收??梢酝ㄟ^(guò)調(diào)用Handler中的remove..方法或者mHandler.removeCallbacksAndMessages(null); 刪除所有的Runnable和Message。
參考
Android消息處理機(jī)制(Handler、Looper、MessageQueue與Message)
Android App 內(nèi)存泄露之Handler