Handler機制到底是個什么東西?(一句話說清楚)

“說一下handler機制”,這句話面試的時候被問過無數(shù)次。但是到底要怎么說,網(wǎng)上卻沒有一個標準答案,很多人洋洋灑灑一大篇加各種圖,實在讓人望而生畏,你是讓我面試的時候背這么一大篇嗎?

其實真的沒有那么復(fù)雜,干貨上前,標準答案:

   Handler機制主要由Handler,Looper,MeesageQueue組成。
   Looper在程序啟動時即創(chuàng)建并不斷的在循環(huán),直到Handler有消息發(fā)送到MessageQueue時,
   Looper取出消息且回調(diào)給Handler來處理。

怎么樣,洋洋灑灑一大篇看不懂,這么幾句話,是不是簡單多了?

什么,你說不夠深入?

好吧,那我們來深入一下,《How to read a book》講,一定要提出問題,那我們就來深入的提出幾個問題:

1.Looper是個什么玩意,它是怎么創(chuàng)建的?它是什么時候開始循環(huán)的?

2.Handler是怎么把發(fā)送消息讓Looper知道的?

3.Looper又是怎樣取出消息且回調(diào)給Handler來處理的?

在這里,我們必須閱讀一下源碼了,我們來看這三個主要組成的其一Looper類,打開代碼,是不是很長一大片不知道怎么入手?哎呀好困難怎么辦。答案是,一點也不困難,因為我們閱讀源碼,并不是一行一行讀,而是只要看核心方法就夠了,什么是核心方法呢?Looper有倆個,prepare(),這個單詞的意思是準備;還有一個loop(),這個單詞的意思是循環(huán)。

我們來看perpare()

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    final MessageQueue mQueue;
    final Thread mThread;

    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));
    }
    
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

是的沒有錯,就這些了,我們可以看到它做了三件事情:
第一、“sThreadLocal.set(new Looper(quitAllowed));” 把new出來的Looper給塞到ThreadLocal里面,我們不難理解ThreadLocal就是一個類似HashMap的東東;
第二、“ mQueue = new MessageQueue(quitAllowed);” new了一個MessageQueue;
第三、“mThread = Thread.currentThread();” 獲取當前線程的引用。

接下來是loop()

   public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            try {
                msg.target.dispatchMessage(msg);
            } finally {
           
            }
            msg.recycleUnchecked();
        }
    }

把不重要的代碼刪掉,是不是一目了然了,已經(jīng)不用多解釋了吧?

我們再來看一個類,ActivityTread的main[]方法,這個地方是程序啟動時就會調(diào)用的

    public static void main(String[] args) {
        Looper.prepareMainLooper();
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

    class Looper{
      public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
}

一目了然,也就是說,程序啟動時,先prepare() new出來一個Looper,并且把它塞到ThreadLocal里面,以后在同一個線程要用的時候都從里面拿,避免創(chuàng)建多個Looper,然后就開始了loop(),死循環(huán)之路,也就是說程序無時無刻不在loop(),然后msg=null的時候,return,直到發(fā)現(xiàn)有了msg,msg.target.dispatchMessage(msg);交給msg的target,也就是handler來處理。

我們再來看下Handler的源碼,我們先看Handler的構(gòu)造函數(shù)

    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()");
        }
        mQueue = mLooper.mQueue;
    }

Looper.myLooper,正是我們剛才說的,從ThreadLocal里面拿出本線程已有的Looper,然后MessageQueue,也是原來Looper里面的那個MessageQueue,接下來是Handler發(fā)送消息的方法,sendMessageAtTime

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);
    }
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        return queue.enqueueMessage(msg, uptimeMillis);
}

不難理解,Handler并沒有真正意義的去“發(fā)送”,而是把消息放到了MessageQueue中而已。

最后,我們來看下Handler如何處理的消息,dispatchMessage

    public void handleMessage(Message msg) {
    }
    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
            handleMessage(msg);
    }

還記不記得,Loop.loop()中,一旦發(fā)現(xiàn)MessageQueue有值,就會調(diào)用msg.target.dispatchMessage(msg);走的就是這里啦,還記不記得我們平時寫Handler的時候,一般都是這樣

     Handler mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
            
            }
        };

重寫的就是上面這個方法啦,至此,我們來回顧一下上面三個問題:

1.Looper是個什么玩意,它是怎么創(chuàng)建的?它是什么時候開始循環(huán)的?

2.Handler是怎么發(fā)送消息讓Looper知道的?

3.Looper又是怎樣取出消息且回調(diào)給Handler來處理的?

如果對照源碼仔細看了本文,相信這幾個問題已經(jīng)不難啦,而且你也學(xué)會了如何真正的閱讀源碼,那就是抓住主線而忽略掉不重要的部分,如果對你有幫助,點個喜歡吧!

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

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