由淺入深全面分析Handler機(jī)制原理之源碼

前言

在Android中提供了一種異步回調(diào)機(jī)制Handler。在開發(fā)中,我們都會接觸到線程間的通信,也就是在子線程處理一些事務(wù)操作,處理完成后,通過Handler發(fā)送消息通知主線程根據(jù)事務(wù)消息更新UI。在源碼中也到處看到Handler的身影。有時(shí)候開發(fā)過程中往往只知道怎么去使用它,從而不很少去了解它的原理與特性,下面我們通過Handler的使用去探索Handler的原理與特性。

目錄

  • Handler的簡單使用
  • Handler機(jī)制的構(gòu)成
  • Handler機(jī)制組成成員之間的關(guān)系
  • Handler機(jī)制原理

先一張圖,對下面在分析的內(nèi)容有一個整體了解:


Handler的簡單使用

我們模擬線程間的消息通信,在子線程中發(fā)出一條信息,在UI線程接收這個條消息,并打印出來,當(dāng)然在開發(fā)中,可能業(yè)務(wù)不一樣,但都是從子線程發(fā)送消息,在主線程更新UI。

/**
  * Author: 安仔夏天很勤奮
 * Date: 2020/09/20
 * Desc: 
 */
public class HandlerActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);
    }

    //此處理程序類應(yīng)該是靜態(tài)的,否則可能會發(fā)生泄漏.(匿名Handler)
    Handler mHandler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            //更新UI 
            Log.e("lu","what: "+msg.what+"    obj :"+msg.obj);
        }
    };

    public void sendThreadMessage(View view) {
        //在異步中,Handler發(fā)送消息,讓UI線程處理
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message m = new Message();
                m.arg1=2;
                m.obj="我是子線程的obj";
                m.what=1;
                mHandler.sendMessage(m);
            }
        }).start();
    }
}

簡單的使用Handler是不是很簡單,但是這樣創(chuàng)建一個Handler匿名內(nèi)部類,會存在內(nèi)存泄漏風(fēng)險(xiǎn)。

Handler為什么會有內(nèi)存泄漏風(fēng)險(xiǎn)?

當(dāng)我們創(chuàng)建一個Handler匿名內(nèi)部類時(shí),編輯器為我們標(biāo)出了黃色,并且提示如下:

This Handler class should be static or leaks might occur (anonymous android.os.Handler) less... (Ctrl+F1)
Since this Handler is declared as an inner class, it may prevent the outer class from being garbage collected. If the Handler is using a Looper or MessageQueue for a thread other than the main thread, then there is no issue. If the Handler is using the Looper or MessageQueue of the main thread, you need to fix your Handler declaration, as follows: Declare the Handler as a static class; In the outer class, instantiate a WeakReference to the outer class and pass this object to your Handler when you instantiate the Handler; Make all references to members of the outer class using the WeakReference object.
由于handler定義為內(nèi)部類,可能會阻止GC。如果handler的Looper或MessageQueue 非主線程,那么沒有問題。如果handler的Looper或MessageQueue 在主線程,那么需要按如下定義:定義handler為靜態(tài)內(nèi)部類,當(dāng)你實(shí)例化handler的時(shí)候,傳入一個外部類的弱引用,以便通過弱引用使用外部類的所有成員。

解決創(chuàng)建一個Handler匿名內(nèi)部類存在內(nèi)存泄漏風(fēng)險(xiǎn)的一個寫法,代碼如下:

/**
 * Author: 安仔夏天很勤奮
 * Date: 2020/09/20
 * Desc: 
 */
public class HandlerActivity extends AppCompatActivity {
    MyHandler myHandler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);
        myHandler = new MyHandler(this);
    }

    static class MyHandler extends Handler{
        //弱引用
        WeakReference<HandlerActivity> weakReference;
        public MyHandler(HandlerActivity activity){
            weakReference = new WeakReference<>(activity);
        }
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            HandlerActivity activity = weakReference.get();
            if (activity !=null && !activity.isFinishing()){
                //更新UI
                Log.e("lu","what: "+msg.what+"    obj :"+msg.obj);
                activity.refreshUI();
            }
        }
    }
    
    private void refreshUI(){ }

    public void sendThreadMessage(View view) {
        //在異步中,Handler發(fā)送消息,讓UI線程處理
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 發(fā)送一個消息,延時(shí)2分鐘處理消息,此時(shí)handler是持有activity引用的
                myHandler.sendEmptyMessageDelayed(1,120_1000);
            }
        }).start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(myHandler!=null){
            myHandler.removeCallbacksAndMessages(null);
        }
    }
}
  • Handler導(dǎo)致activity內(nèi)存泄露的原因

    當(dāng)Handler發(fā)送的一條消息,如果這條消息是延遲很久的,那么還在當(dāng)退出組件(如Activity.finish())時(shí),Handler發(fā)送的消息依然隊(duì)列中,那么消息隊(duì)列的消息到時(shí)間了,就會由Handler進(jìn)行分發(fā)處理,若此時(shí)Handler聲明為內(nèi)部類(非靜態(tài)內(nèi)部類),我們知道內(nèi)部類天然持有外部類的實(shí)例引用,當(dāng)GC垃圾回收機(jī)制被調(diào)用時(shí),那么就會導(dǎo)致組件activity無法回收,從而導(dǎo)致activity泄露。(關(guān)于GC回收機(jī)制的討論就不展開討論了。)

  • 使用靜態(tài)內(nèi)部類的作用

    因?yàn)殪o態(tài)內(nèi)部類不持有外部類的引用,所以使用靜態(tài)的Handler不會導(dǎo)致組件activity的泄露。Java的引用有四大引用:強(qiáng)引用,弱引用,軟引用,虛引用(關(guān)于Java的引用作用就不展開討論了)。

  • 使用static修飾同時(shí),為什么還要用WeakReference 包裹外部類的對象?

    因?yàn)槲覀冃枰褂猛獠款惖某蓡T,由于不持有外部類的引用,怎么辦呢,只能傳入外部類引用(強(qiáng)引用),如通過"activity. "獲取變量方法等,如果直接使用強(qiáng)引用,顯然會導(dǎo)致activity泄露。使用弱引用,當(dāng)組件activity銷毀時(shí),GC垃圾回收機(jī)制被調(diào)用時(shí),根據(jù)GC Root可達(dá)性分析,那么弱引用的對象就會被回收。

  • 退出組件件時(shí),清空。

    退出組件時(shí),要及時(shí)調(diào)用Handler.removeCallbacksAndMessages(null)清空。

Handler機(jī)制的構(gòu)成

Handler類

Handler機(jī)制有那些相關(guān)的類,我們從Handler的構(gòu)造函數(shù)與mHandler.sendMessage(Message msg)函數(shù)作為入口查看源碼。首先看看Handler類的構(gòu)造函數(shù)源碼,由于Handler重載了多個構(gòu)造函數(shù),我們就取Handler()作為切入點(diǎn):

public Handler() {
    this(null, false);
}
public Handler(@Nullable Callback callback, boolean async) {
    //...省略部分代碼
    mLooper = Looper.myLooper();//獲取Looper
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
            + " that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;//獲取消息隊(duì)列MessageQueue
    mCallback = callback;//初始化回調(diào)
    mAsynchronous = async;//是否為異步
}

當(dāng)我們直接new Handler()時(shí),內(nèi)部直接調(diào)用this(null, false),其實(shí)Handler重載了多個構(gòu)造函數(shù),最終還是Handler(Callback callback, boolean async)構(gòu)造函數(shù),當(dāng)然我們還可以調(diào)用Handler(Looper looper, Callback callback, boolean async)等構(gòu)造函數(shù) 。從Handler構(gòu)造函數(shù)中看出,Handler的成員變量mLooper、mQueue、mCallback、mAsynchronous都是賦值操作,所以Handler持有著一個Looper對象、MessageQueue對象、Callback回調(diào)。

Looper初始化時(shí)機(jī)

Looper.prepare()函數(shù)

在上述使用Handler時(shí)的Handler構(gòu)造函數(shù)中看出, mLooper并不是直接new出一個Looper對象,而是在Handler構(gòu)造函數(shù)中直接獲取Looper對象(mLooper = Looper.myLooper()),那么Looper對象在那里創(chuàng)建了Looper對象呢。查看Looper源碼:

public final class Looper {
    //quitAllowed  MessageQueue是否允許退出
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);//創(chuàng)建MessageQueue對象
        mThread = Thread.currentThread();//Looper 綁定當(dāng)前線程
    }
    public static void prepare() {
        prepare(true);
    }
    // quitAllowed  MessageQueue是否允許退出
    private static void prepare(boolean quitAllowed) {
        //如果不為null,說明當(dāng)前線程已經(jīng)存在對應(yīng)的Looper對象,報(bào)出異常,保證一個線程只有一個Looper對象
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));//創(chuàng)建一個Looper對象并設(shè)置給ThreadLocal
    }
//獲取當(dāng)前線程的Looper對象
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

}

從源碼我們可以看出,Looper是一個私有的構(gòu)造函數(shù),則不能在其他地方new出一個Looper對象,目的是為了確保一個Handler對應(yīng)一個Looper。但Looper類中提供了兩個prepare重載函數(shù),最終還是調(diào)用prepare(boolean quitAllowed)函數(shù),所以創(chuàng)建普通線程(子線程)創(chuàng)建Looper對象調(diào)用prepare()即可。prepare(quitAllowed)函數(shù)使用ThreadLocal 保存當(dāng)前Looper對象。關(guān)于ThreadLocal的作用,先放一旁,下面再討論分析。

主線程Looper創(chuàng)建的時(shí)機(jī)

基于上述使用例子,主線程的Looper什么時(shí)候創(chuàng)建的呢,當(dāng)我們點(diǎn)擊桌面圖標(biāo)啟動APP時(shí),會啟動一個AMS(ActivityManagerService)如果還沒有創(chuàng)建APP進(jìn)程,那么就是Zygote出一個進(jìn)程,創(chuàng)建一個進(jìn)程對應(yīng)的JVM,然后調(diào)用ActivityThread.main()函數(shù)啟動Activity(這里涉及到APP的啟動流程就不展開了,感興趣的可以自行查閱學(xué)習(xí))。在一個APP中只有一個主線程,那么主線程的Looper也只有一個,而ActivityThread就是我們常說的主線程或UI線程,ActivityThread的main函數(shù)是整個APP的入口,所以主線程的Looper的創(chuàng)建時(shí)機(jī)就在ActivityThread的main函數(shù)里??闯梢幌略创a:

public static void main(String[] args) {
    //...省略前面的代碼
    Looper.prepareMainLooper();//主線程的Looper初始化
    //...省略部分代碼
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);//建立Binder通道 (創(chuàng)建新線程) 
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();//初始化主線程的Handler
    }
    //...省略部分代碼
    Looper.loop();//開始輪詢
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

public static void prepareMainLooper() {
    prepare(false);//初始化主線程的Looper
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper(); //主線程Looper初始化完成后賦值給sMainLooper
    }
}

從上述的源代碼中可以看出,創(chuàng)建主線程Looper輪詢器創(chuàng)建的過程主路線為:ActivityThread.main() -- > Looper.prepareMainLooper() --> Looper.prepare(false) --> sThreadLocal.set(new Looper(quitAllowed)) --> thread.getHandler() 初始化主線程Handler--> Looper.loop()

用一張圖來展示,更加易懂:


在主線程或子線程初始化Looper,需要注意以下幾點(diǎn):

  • 子線程的Looper.prepare() 函數(shù)的quitAllowed默認(rèn)為true,表示MessageQueue允許退出;而主線程的 Looper.prepareMainLooper()里的Looper.prepare(false)函數(shù)的quitAllowed為false,表示MessageQueue不允許退出。這里的quitAllowed參數(shù)傳遞給MessageQueue對象,當(dāng)調(diào)用MessageQueuec對象的quit函數(shù)時(shí),會判斷這個參數(shù),如果是主線程,也就是quitAllowed參數(shù)為false時(shí),會拋出異常。

    void quit(boolean safe) {
            if (!mQuitAllowed) {//主線程不可能退出消息隊(duì)列
                throw new IllegalStateException("Main thread not allowed to quit.");
            }
            synchronized (this) {
                if (mQuitting) {
                    return;
                }
                mQuitting = true;
                if (safe) {
                    removeAllFutureMessagesLocked();
                } else {
                    removeAllMessagesLocked();
                }
                // We can assume mPtr != 0 because mQuitting was previously false.
                nativeWake(mPtr);
            }
        }
    
  • 主線程Looper初始化成功后,賦值給了成員變量sMainLooper,這個成員的作用就是向其他線程提供主線程的Looper對象。所以說不管在那里都可以通過調(diào)用Looper.getMainLooper()函數(shù)能獲取主線程的Looper對象的原因。

  • 主線程的Handler的初始化。從源碼上看出主線程的Handler作為ActivityThread的mH成員變量,直接final H mH = new H()。而H處理的事務(wù)涉及到Activity的啟動流程,生命周期等等。(Activity的啟動流程,生命周期就不展開討論了,感覺興趣的可以自行研究。)

    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();//初始化主線程的Handler
    }
    
    final H mH = new H()
    @UnsupportedAppUsage
    final Handler getHandler() {
        return mH;
    }
    

主線程的Looper、Handler都初始化完成后,調(diào)用Looper.loop()函數(shù)開始從MessageQueue中不斷輪詢,獲取Message。我們從Looper.loop()函數(shù)分析。

Looper.loop()函數(shù)

在Looper.loop()函數(shù)不斷輪詢,是通過MessageQueue.next()函數(shù)不斷輪詢,取出對應(yīng)的消息。源碼如下:

public static void loop() {
    //通過sThreadLocal.get()獲取剛剛初始化好的Looper對象
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    //獲取Looper對應(yīng)的消息隊(duì)列MessageQueue
    final MessageQueue queue = me.mQueue;

    //...省略部分代碼

    for (;;) {//不斷循環(huán)從消息隊(duì)列中取出消息
        Message msg = queue.next(); //有可能阻塞
        if (msg == null) {//沒有消息,則退出消息隊(duì)列
            // No message indicates that the message queue is quitting.
            return;
        }
        //...省略部分代碼
        try {
            //msg.target就是Handler,把獲取到的消息分發(fā)出去
            msg.target.dispatchMessage(msg);
            end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
        } finally {
            if (traceTag != 0) {
            Trace.traceEnd(traceTag);
            }
        }
        //...省略部分代碼
        msg.recycleUnchecked();//回收Message
    }
}

從queue.next()獲取Message, 調(diào)用msg.target.dispatchMessage(msg)函數(shù)把Message分發(fā)出去,然后調(diào)用msg.recycleUnchecked()回收Message對象。

Message的創(chuàng)建

創(chuàng)建Message有兩種方式:我們可以直接new Message(),也可以Message msg = Message.obtain(),當(dāng)然Message類中還重寫了很多obtain(xxx)函數(shù)。

Message m = new Message();
m.arg1=2;
m.obj="我是子線程的obj";
m.what=1;
mHandler.sendMessage(m);

Message mm = Message.obtain();
mm.obj="我是子線程的obj";
mm.what=1;
mHandler.sendMessage(mm);

既然可以new Message()創(chuàng)建對象,為什么還提供了Message.obtain()獲取對象,其實(shí)這里涉及到對象復(fù)用設(shè)計(jì)(享元設(shè)計(jì)模式)。對象復(fù)用設(shè)計(jì)先放一放,下面再討論分析

Handler發(fā)送Message

Handler類中定義了一系列發(fā)送Message的函數(shù),我們就選取兩個較為常用的作為切入點(diǎn),進(jìn)入mHandler.sendMessage(Message msg)或mHandler.sendEmptyMessage(1)的源碼:

Message msg = new Message;
msg.what = 2;
mHandler.sendMessage(msg);//切入點(diǎn)一
mHandler.sendEmptyMessage(1);//切入點(diǎn)二

//切入點(diǎn)一
public final boolean sendMessage(Message msg){
    return sendMessageDelayed(msg, 0);
}
//切入點(diǎn)二
public final boolean sendEmptyMessage(int what){
    return sendEmptyMessageDelayed(what, 0);
}
//delayMillis 延時(shí)時(shí)間
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
    Message msg = Message.obtain();//獲取一個消息Message 為什么不直接new出來?下面會作出解答
    msg.what = what;
    return sendMessageDelayed(msg, delayMillis);
}

public final boolean sendMessageDelayed(Message msg, long delayMillis){
    if (delayMillis < 0) {//延時(shí)時(shí)間小于0毫秒,默認(rèn)為0毫秒
        delayMillis = 0;
    }
    //延時(shí)時(shí)間為系統(tǒng)更新時(shí)間(毫秒)
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//按時(shí)間發(fā)送消息
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
            this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    return enqueueMessage(queue, msg, uptimeMillis);
}

//最終調(diào)用enqueueMessage函數(shù),把消息插入到消息隊(duì)列中
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    //this就是Handler Message中持有一個Handler
    //為發(fā)送消息出隊(duì)列交給handler處理埋下伏筆。
    msg.target = this;
    if (mAsynchronous) {//是否是異步
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);//調(diào)用消息隊(duì)列的入隊(duì)函數(shù)
}

從源碼分析得知,不管Handler調(diào)用sendXXX()還是postXXX()發(fā)送Message,都會調(diào)用Handler.enqueueMessage()函數(shù),把當(dāng)前的Handler對象賦值給msg.target,如果是異步,同時(shí)把Message的flags為異步,最終調(diào)用MessageQueue.enqueueMessage()函數(shù),函數(shù)中的參數(shù)queue,是構(gòu)造函數(shù)里初始化的;參數(shù)msg,是Message,參數(shù)uptimeMillis:是更新時(shí)間,如果不設(shè)置更新時(shí)間則以系統(tǒng)更新時(shí)間,否則使用設(shè)置的更新時(shí)間。下面用一張Handler發(fā)送消息的關(guān)系圖片加深印象和解理:


MessageQueue類

MessageQueue.enqueueMessage函數(shù)

Handler發(fā)送消息時(shí),最終調(diào)用MessageQueue類的 enqueueMessage函數(shù)。

//MessageQueue.java
boolean enqueueMessage(Message msg, long when) {
   synchronized (this) {
        if (mQuitting) {
            msg.recycle();//退出,則清空消息
            return false;
        }

        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {
            //頭消息 如果阻塞,喚醒隊(duì)列事件
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            //是阻塞狀態(tài),Message沒有綁定Handler,是異步,三者都成立時(shí),則需要喚醒
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {//遍歷,按延時(shí)時(shí)間從小到大排序
                prev = p;
                p = p.next;
                //沒有消息或延時(shí)時(shí)間比隊(duì)列中的消息的延時(shí)時(shí)間都小,退出循環(huán)
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {//是喚醒狀態(tài),并是異步,則入隊(duì)后,不需要喚醒隊(duì)列
                    needWake = false;
                }
            }
            //插入合適的位置
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }
        if (needWake) {//調(diào)用Native的喚醒機(jī)制
            nativeWake(mPtr);
        }
    }
    return true;
}

當(dāng)消息入隊(duì)時(shí),首先會判斷,如果退出,則清空消息。如果是第一個消息、新消息沒有延遲、新消息延遲時(shí)間小于隊(duì)列第一個消息的,根據(jù)needWake是否調(diào)用nativeWake()函數(shù),對這個消息進(jìn)行處理(也就是喚醒MessageQueue.next()獲取消息)。如果消息不為空并時(shí)間大于當(dāng)前時(shí)間,會依次遍歷消息隊(duì)列,將消息按延遲時(shí)間插入消息隊(duì)列適應(yīng)的位置(按延遲時(shí)間從小到大排序插入消息)。從源碼中我們可能看出, MessageQueue 實(shí)際上在里面維護(hù)著一個 Message 構(gòu)成的單鏈表(因?yàn)橹挥衝ext節(jié)點(diǎn)),每次插入Message都會按時(shí)間順序進(jìn)行插入, MessageQueue 中的 Message 都是按照時(shí)間排好序的,這樣就使得循環(huán)取出 Message 的時(shí)候只需要一個個地從前往后拿即可,這樣 Message 可以按時(shí)間先后順序被消費(fèi),也表明MessageQueue是一個優(yōu)先級隊(duì)列。Handler的喚醒機(jī)制放一放,下面再討論分析

MessageQueue.next函數(shù)

在Looper.loop函數(shù)中,一個死循環(huán)不斷循環(huán)取到消息就會消費(fèi),不斷循環(huán)取到消息其實(shí)是不斷的從MessageQueue.next()輪詢獲取Message。

Message next() {
    //...省略部分代碼
    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }
        nativePollOnce(ptr, nextPollTimeoutMillis);//根據(jù)nextPollTimeoutMillis是阻塞還喚醒
        synchronized (this) {
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            //優(yōu)先處理異步信息(同步屏障機(jī)制)
            if (msg != null && msg.target == null) {
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    // 當(dāng)頭消息延遲時(shí)間大于當(dāng)前時(shí)間,阻塞消息要到延遲時(shí)間和當(dāng)前時(shí)間的差值
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // 取到一個消息
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;
                }
            } else {
                nextPollTimeoutMillis = -1;//隊(duì)列已無消息,一直阻塞
            }
        }
        //...省略部分代碼
        //如果第一次空閑,則獲取運(yùn)行的待處理數(shù)。
        //只有當(dāng)隊(duì)列為空或隊(duì)列中的第一條消息(可能是一個屏障)將來要處理時(shí),才會運(yùn)行空閑句柄。
        if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
        if (pendingIdleHandlerCount <= 0) {
             //沒有要運(yùn)行的空閑處理程序。一直阻塞
              mBlocked = true;
              continue;
         }

        //...省略部分代碼
        pendingIdleHandlerCount = 0;
        nextPollTimeoutMillis = 0;
    }
}

Looper.loop輪詢器,真正干活的是MessageQueue.next()函數(shù),剛開始初始化Looper對象,輪詢MessageQueue時(shí),next函數(shù)獲取Message時(shí),MessageQueue隊(duì)列中并沒有Message,調(diào)用nativePollOnce(ptr, nextPollTimeoutMillis),進(jìn)行阻塞,nextPollTimeoutMillis參數(shù)為-1。阻塞的處理在Native層處理。Handler的阻塞機(jī)制放一放,下面再討論分析

如果消息不為null,同時(shí)msg.target為null,會一直不斷遍歷Message,直到遇到是異步標(biāo)記,則取出消息。在這里我們都會覺得奇怪,Handler.enqueueMessage函數(shù)里msg.target=this,都已經(jīng)賦值了,為什么msg.target還會為null呢,這是與Handler的同步屏障有關(guān),這里先放一放,下面再討論分析

判斷如果當(dāng)前消息是否到了應(yīng)該發(fā)送的時(shí)間,如果到了應(yīng)該發(fā)送的時(shí)間,就會將該消息取出并返回,否則僅僅只是將 nextPollTimeoutMillis 置為了剩余時(shí)長,這個時(shí)長與Integer.MAX_VALUE做了防止Int越界操作。nextPollTimeoutMillis 阻塞對應(yīng)時(shí)長,時(shí)間到可被底層喚醒,獲取消息并消費(fèi)掉。

基于第一次運(yùn)行MessageQueue 為空,或者消息待處理狀態(tài),mBlocked = true繼續(xù)阻塞,則會嘗試去執(zhí)行一些 idleHandler,并在執(zhí)行后將 pendingIdleHandlerCount 置為 0避免下次再次執(zhí)行。

下面我們通過一張MessageQueue入隊(duì)出隊(duì),加深印象:


Handler通過dispatchMessage分發(fā)處理Message

當(dāng)Looper.loop()函數(shù)獲取到一個Message,則調(diào)用Handler.dispatchMessage(msg)函數(shù)分發(fā)處理這消息。

public static void loop() {
    for (;;) {//不斷循環(huán)從消息隊(duì)列中取出消息
        Message msg = queue.next(); //有可能阻塞
        //...省略部分代碼
        try {
            //msg.target就是Handler,把獲取到的消息分發(fā)出去
            msg.target.dispatchMessage(msg);
        } finally { }
        //...省略部分代碼
        msg.recycleUnchecked();//回收Message
    }
}
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            //如果設(shè)置了回調(diào),讓實(shí)現(xiàn)Callback的實(shí)現(xiàn)類去處理這條消息
            //如果返回true,不處理Handler的handleMessage函數(shù),否則處理Handler.handleMessage函數(shù)
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

Handler.dispatchMessage()函數(shù)是怎么分發(fā)處理消息的,從源碼也得出,就是作為判斷讓誰去處理這條消息。如果msg.callback不為null,讓Message里的callback處理,那么msg.callback是那里賦值的,上面Handler發(fā)送消息里重載了不同的發(fā)送消息的函數(shù),就看Handler.post(Runnable r)函數(shù)源碼作為切入點(diǎn)(其他切入點(diǎn)就不列舉了),一切皆明白。

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;
}

Handler.Callback作用

msg.callback != null 其實(shí)msg.callback 就是一個Runnable,交給了實(shí)現(xiàn)Runnable的類去處理這條消息。

mCallback != null ,如果設(shè)置了Handler.mCallback 回調(diào),mCallback.handleMessage(msg)返回true,讓實(shí)現(xiàn)Handler.Callback的實(shí)現(xiàn)類去處理這條消息,而Handler.handleMessage()則不處理這條消息,如果返回是false,那么Handler.handleMessage()也處理這條消息。

Handler handler = new Handler(Looper.getMainLooper(),callback){
    @Override
    public void handleMessage(@NonNull Message msg) {
        Log.e("lu", "Handler handleMessage");
        super.handleMessage(msg);
    }
};

Message msg = new Message();
msg.what=1;
handler.sendMessage(msg);

Handler.Callback callback = new Handler.Callback() {
    @Override
    public boolean handleMessage(@NonNull Message msg) {
        Log.e("lu", "callback handleMessage");
        return true;//返回為true,不會執(zhí)行Handler handleMessage方法,返回為false會執(zhí)行
    }
};

注意:Handler.Callback.handleMessage,返回為true,不會執(zhí)行Handler handleMessage方法,返回為false會執(zhí)行。

Handler機(jī)制組成成員

從Handler的構(gòu)造函數(shù)和Handler發(fā)送Message這兩步得出,與Handler機(jī)制組成成員類有:Handler、Message、MessageQueue、Looper。下面分析這些成員之間的關(guān)系。

Handler獲取當(dāng)前線程的Looper對象,Looper是用來從存放Message的MessageQueue中取出Message,接著Handler進(jìn)行Message分發(fā)處理。

  • Handler:是消息(Message)的處理者,負(fù)責(zé)消息的發(fā)送,和接收消息的處理。
  • Message:消息,可以理解為線程間交流的數(shù)據(jù)。
  • Looper:是每個線程里的消息隊(duì)列(MessageQueue)管家一樣,用于輪詢消息隊(duì)列,一個線程只有一個Looper。
  • MessageQueue:消息隊(duì)列是存儲消息和管理消息。

Handler機(jī)制組成成員之間的關(guān)系

Handler與Message之間的關(guān)系

public final class Message implements Parcelable {
    Handler target;
}
public class Handler{
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
}

從源代碼可以看出,創(chuàng)建一個Message對象時(shí)可以設(shè)置其成員target,進(jìn)行Handler與Message綁定,如果創(chuàng)建Message對象時(shí)不綁定,那么Handler發(fā)送Message時(shí),調(diào)用enqueueMessage函數(shù)時(shí),自動進(jìn)行綁定。

Handler與Looper之間的關(guān)系

public class Handler{
    public Handler(Callback callback, boolean async) {
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
    }
}

public final class Looper{
   public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
}

從源碼分析得出,在ThreadLoocal本地變量中取出一個Looper對象,在Handler結(jié)構(gòu)函數(shù)里,將當(dāng)前線程的Looper對象賦值給Handler成員mLooper,實(shí)行綁定。

Looper、Thread、MessageQueue之間的關(guān)系

public final class Looper{
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
    public static void prepare() {
        prepare(true);
    }
    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
}

從Looper的構(gòu)造函數(shù)看出,直接創(chuàng)建一個MessageQueue對象并賦值給Looper.mQueue,同時(shí)當(dāng)前線程賦值給Looper.mThread,然而Looper對象是使用ThreadLocal本地變量存放,ThreadLocal的使用是線程隔離,因此Thread、Looper、MessageQueue是1:1:1關(guān)系,也就是一個Looper對象綁定一個MessageQueue和一個線程。關(guān)于ThreadLocal討論放一放,下面再討論分析

MessageQueue與Message之間的關(guān)系

public class Hander{
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        //...省略部分代碼 
        return queue.enqueueMessage(msg, uptimeMillis);
    }
}

public final class MessageQueue{
    boolean enqueueMessage(Message msg, long when) {
        //...省略部分代碼 
            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
            //...省略部分代碼     
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
               //...省略部分代碼 
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }
        //...省略部分代碼 
        }
        return true;
    }
}

從Handler發(fā)送Message,最后調(diào)用MessageQueue.enqueueMessage函數(shù),可以看得出,MessageQueue類中持有一個Messages成員變量mMessages,然后enqueueMessage函數(shù)里Message p = mMessages,最后將傳入的Message存放到MessageQueue.mMessages中。也就是說MessageQueue是存放Message的一個容器。

Handler機(jī)制原理

通過上述源碼分析Handler機(jī)制過程中,我們很容易得出Handler機(jī)制的原理主線路:從Handler類 -->綁定一個Looper和MessageQueue --> Handler發(fā)送Message -->Message綁定Handler --> MessageQueue保存Message --> Looper.loop一直在輪詢 --> MessageQueue取出Message --> Handler.dispatchMessage分發(fā)消息 --> Handler處理消息 Handler.HandleMessage

通過畫一張Handler機(jī)制流程圖,加深印象,更容易理解。


Handler機(jī)制的難點(diǎn)

由于文章邊幅太長,不利于閱讀,關(guān)于Handler以下的的難點(diǎn),另寫一篇文章:

  • prepare()函數(shù)中,使用ThreadLocal存放Looper對象,ThreadLocal的作用。
  • Message使用對象復(fù)用池(享元設(shè)計(jì)模式)
  • 內(nèi)存共享(如何切換線程的)
  • Handler的阻塞/喚醒機(jī)制
  • Handler的同步屏障

總結(jié)

  • Handler的簡單使用,注意內(nèi)存泄漏風(fēng)險(xiǎn)。
  • 弄清楚Handler機(jī)制的構(gòu)成成員
  • 弄清楚Handler機(jī)制的構(gòu)成成員之間的調(diào)用過程
  • 理清楚Handler機(jī)制成員之間的關(guān)系
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。

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