Handler

基本要素

  • Message:消息的表示
  • MessageQueue:消息隊(duì)列
  • Looper:消息循環(huán),用于從消息隊(duì)列中取出消息
  • Handler:消息處理

Handler的使用

  1. 初始化
    為了使用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í)所在的線程。
  1. 擴(kuò)展Handler或者實(shí)現(xiàn)Handler.Callback接口作為Handler的構(gòu)造參數(shù),并實(shí)現(xiàn)handleMessage方法。實(shí)例化Handler子類時(shí),應(yīng)該在prepare和loop之間進(jìn)行。

  2. 獲得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不能被垃圾回收。
解決辦法:

  1. Handler作為靜態(tài)類或外部類實(shí)現(xiàn)
  2. Activity作為參數(shù)傳遞給Handler的構(gòu)造器
  3. Handler內(nèi)部使用軟引用或弱引用來(lái)保存Activity。
  4. 在handleMessage或run方法中使用Activity時(shí),應(yīng)該判斷它是否為空。
  5. 另外,在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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容