Handler 消息機(jī)制詳解

1. Handler,Looper,MessageQueue,Message他們的作用與關(guān)系

1.1Handler

Handler使您可以發(fā)送和處理[Message](https://developer.android.com/reference/android/os/Message)與線程的關(guān)聯(lián)的Runnable對(duì)象[MessageQueue](https://developer.android.com/reference/android/os/MessageQueue)忆蚀。每個(gè)Handler實(shí)例都與一個(gè)線程和該線程的消息隊(duì)列關(guān)聯(lián)肢预。當(dāng)您創(chuàng)建新的處理程序時(shí)辞做,它會(huì)綁定到[Looper](https://developer.android.com/reference/android/os/Looper)辱魁。它將消息和可運(yùn)行對(duì)象傳遞到該Looper的消息隊(duì)列寝杖,并在該Looper的線程上執(zhí)行它們拨拓。

Handler有兩個(gè)主要用途:(1)計(jì)劃消息和可運(yùn)行對(duì)象在將來(lái)的某個(gè)時(shí)刻執(zhí)行家制;(2)使要在與您自己的線程不同的線程上執(zhí)行的操作排隊(duì)暂雹。
以上是官方翻譯說(shuō)明策治,Handler在我們平常的使用主要是用于異步消息通知脓魏,在子線程中通知主線程做什么事,比ui刷新通惫,或者延時(shí)執(zhí)行某個(gè)操作茂翔。

1.2Message

定義一條消息,其中包含可以發(fā)送到的描述和任意數(shù)據(jù)對(duì)象[Handler](https://developer.android.com/reference/android/os/Handler)履腋。該對(duì)象包含兩個(gè)額外的int字段和一個(gè)額外的對(duì)象字段珊燎,在很多情況下,這些字段使您不必進(jìn)行分配遵湖。

message是消息通知機(jī)制的載體悔政,Handler發(fā)送的信息都在放在Message中。

1.3MessageQueue

Low-level class holding the list of messages to be dispatched by a [Looper](https://developer.android.com/reference/android/os/Looper). Messages are not added directly to a MessageQueue, but rather through [Handler](https://developer.android.com/reference/android/os/Handler) objects associated with the Looper.
You can retrieve the MessageQueue for the current thread with [Looper#myQueue()](https://developer.android.com/reference/android/os/Looper#myQueue()).

消息隊(duì)列延旧,Handler發(fā)送的消息都在它這管理谋国,提供加入消息,和獲取消息的方法

1.4Looper

用于為線程運(yùn)行消息循環(huán)的類(lèi)迁沫。默認(rèn)情況下芦瘾,線程沒(méi)有與之關(guān)聯(lián)的消息循環(huán);要?jiǎng)?chuàng)建一個(gè)集畅,請(qǐng)[prepare()](https://developer.android.com/reference/android/os/Looper#prepare())在要運(yùn)行循環(huán)的線程中調(diào)用 近弟,然后 [loop()](https://developer.android.com/reference/android/os/Looper#loop())讓它處理消息,直到循環(huán)停止為止牡整。
與消息循環(huán)的大多數(shù)交互是通過(guò) [Handler](https://developer.android.com/reference/android/os/Handler)類(lèi)進(jìn)行的藐吮。

Looper可以理解為一個(gè)循環(huán)執(zhí)行某個(gè)操作的類(lèi),這個(gè)類(lèi)是和線程綁定的。它的循環(huán)操作就是不斷的從MessageQueue中將可以發(fā)送的消息拿出來(lái)交給Handler處理

1.5他們之間的關(guān)系

  1. Handler發(fā)送消息 消息到哪了 谣辞?到messageQueue了 Handler(sendMessage)=====message====>MessageQueue
  2. Handler 處理消息 消息哪來(lái)的迫摔? Looper執(zhí)行它的循環(huán)拾取操作 MessageQueue======Message======>Handler(dispatch)
  • Looper有一個(gè)MessageQueue消息隊(duì)列;
  • MessageQueue有一組待處理的Message泥从;
  • Message中有一個(gè)用于處理消息的Handler句占;
  • Handler中有Looper和MessageQueue。

2.源碼解析

2.1 Handler源碼分析

Handler的創(chuàng)建躯嫉,構(gòu)造函數(shù)纱烘。這里講解兩個(gè)最重要的構(gòu)造函數(shù),其他的構(gòu)造方法都是調(diào)用這兩個(gè),發(fā)送消息和處理消息的方法

  /**
     * 使用當(dāng)前線程的Looper進(jìn)行Handler的創(chuàng)建
     * Use the {@link Looper} for the current thread with the specified callback interface
     * and set whether the handler should be asynchronous.
     * <p>
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     * <p>
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
     *
     * @param callback The callback interface in which to handle messages, or null.
     * @param async    If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     *                 each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     * @hide
     */
    public Handler(@Nullable Callback callback, boolean async) {
        //匿名類(lèi)祈餐、內(nèi)部類(lèi)或本地類(lèi)都必須申明為static擂啥,否則會(huì)警告可能出現(xiàn)內(nèi)存泄露
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                        klass.getCanonicalName());
            }
        }
        //獲取當(dāng)前線程的looper對(duì)象,myLooper方法會(huì)在講解Looper時(shí)進(jìn)行說(shuō)明
        mLooper = Looper.myLooper();
        if (mLooper == null) {//當(dāng)我們?cè)谧泳€程中創(chuàng)建Handler,并使用該構(gòu)造方法帆阳,就會(huì)報(bào)該錯(cuò)誤哺壶,
            // 平時(shí)在主線程中創(chuàng)建Handler時(shí),已經(jīng)在創(chuàng)建Activity時(shí)生成了mainLooper,所以不需要?jiǎng)?chuàng)建
            throw new RuntimeException(
                    "Can't create handler inside thread " + Thread.currentThread()
                            + " that has not called Looper.prepare()");
        }
        //相關(guān)屬性賦值蜒谤,獲取消息隊(duì)列
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

    /**
     * 使用自己傳入的Looper對(duì)象創(chuàng)建Handler
     * Use the provided {@link Looper} instead of the default one and take a callback
     * interface in which to handle messages.  Also set whether the handler
     * should be asynchronous.
     * <p>
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     * <p>
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by conditions such as display vsync.
     *
     * @param looper   The looper, must not be null.
     * @param callback The callback interface in which to handle messages, or null.
     * @param async    If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     *                 each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     * @hide
     */
    @UnsupportedAppUsage
    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
        //相關(guān)屬性賦值
        mLooper = looper;
        //獲取消息隊(duì)列
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

結(jié)論:所以從構(gòu)造方法我們就可以知道

  • Handler中包含一個(gè)Looper山宾,LooperQueue
  • 消息發(fā)送分為同步,與異步鳍徽,異步情況用的少
  • looper分為自己傳入资锰,和Handler默認(rèn)獲取兩種。

Handler的創(chuàng)建既然已經(jīng)搞清楚了阶祭,就在看看它的消息發(fā)送功能,發(fā)送功能只分析比較重要的幾個(gè)方法

sendMessageAtTime發(fā)送消息在某個(gè)時(shí)間點(diǎn)

/**
     * 發(fā)送消息 在某個(gè)時(shí)間
     * Enqueue a message into the message queue after all pending messages
     * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
     * Time spent in deep sleep will add an additional delay to execution.
     * You will receive it in {@link #handleMessage}, in the thread attached
     * to this handler.
     *
     * @param uptimeMillis The absolute time at which the message should be
     *                     delivered, using the
     *                     {@link android.os.SystemClock#uptimeMillis} time-base.
     * @return Returns true if the message was successfully placed in to the
     * message queue.  Returns false on failure, usually because the
     * looper processing the message queue is exiting.  Note that a
     * result of true does not mean the message will be processed -- if
     * the looper is quit before the delivery time of the message
     * occurs then the message will be dropped.
     */
    public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;//獲取消息隊(duì)列
        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);//加入消息到隊(duì)列
    }

getPostMessage绷杜,將Runable轉(zhuǎn)換成Message,相當(dāng)于可以發(fā)送一個(gè)Runable接口濒募,又相當(dāng)于將一段Runable中運(yùn)行的代碼到消息隊(duì)列中接剩,又相當(dāng)于這段代碼運(yùn)行的線程是在Looper所在的線程中。

 /**
     * 將Runable轉(zhuǎn)換成Message的方法
     *
     * @param r 傳入一個(gè)Runable接口
     * @return 返回一個(gè)Message對(duì)象
     */
    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

sendMessageAtFrontOfQueue發(fā)送消息到隊(duì)列頭部

/**
     * 發(fā)送一個(gè)消息到隊(duì)列最前面  uptimeMillis傳0 即可
     * Enqueue a message at the front of the message queue, to be processed on
     * the next iteration of the message loop.  You will receive it in
     * {@link #handleMessage}, in the thread attached to this handler.
     * <b>This method is only for use in very special circumstances -- it
     * can easily starve the message queue, cause ordering problems, or have
     * other unexpected side-effects.</b>
     *
     * @return Returns true if the message 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 sendMessageAtFrontOfQueue(@NonNull Message msg) {
        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, 0);
    }

enqueueMessage萨咳,加入消息到隊(duì)列

    /**
     * 加入消息到隊(duì)列
     * @param queue 消息隊(duì)列
     * @param msg   消息體
     * @param uptimeMillis  發(fā)送時(shí)間
     * @return  是否加入成功
     */
    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
                                   long uptimeMillis) {
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true); //設(shè)置消息是同步還是異步懊缺,這里可以看出,要么全是同步培他,要么全是異步
        }
        return queue.enqueueMessage(msg, uptimeMillis);//調(diào)用消息隊(duì)列的enqueueMessage方法加入消息
    }

Message的創(chuàng)建

    /**
     * Returns a new {@link android.os.Message Message} from the global message pool. More efficient than
     * creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).
     * If you don't want that facility, just call Message.obtain() instead.
     */
    @NonNull
    public final Message obtainMessage() {
        return Message.obtain(this);
    }

結(jié)論

  • 各種sendMesssage方法最后都會(huì)調(diào)用到MessageQueue的enqueueMessage
  • 可以將Runable封裝成Message鹃两,并發(fā)送到Looper線程處理,也有與Runable匹配的各種sendMessage方法舀凛。
    -Message的創(chuàng)建最好用Handler提供的obtainMessage()方法俊扳,這樣創(chuàng)建的對(duì)象是從對(duì)象池中獲取,減少開(kāi)銷(xiāo)猛遍。

下圖是sendMessage的一個(gè)調(diào)用鏈,便于理解

消息發(fā)送方法鏈

Handler可以sendMessage還可以處理消息dispatchMessage接下來(lái)看看處理消息相關(guān)分析

    /**
     * Handle system messages here.
     */
    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {//如果msg的callBack不為空則交給handleCallback方法處理
            handleCallback(msg);
        } else {
            if (mCallback != null) {//如果Handler的mCallback不為空馋记,這交給mCallback處理
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);//都沒(méi)人管交給Handler 的Handler處理
        }
    }

handleCallback

   private static void handleCallback(Message message) {
        message.callback.run();
    }

handler的handleMessage方法

    /**
     * Subclasses must implement this to receive messages. 常用就是通過(guò)重寫(xiě)該方法實(shí)現(xiàn)消息處理邏輯
     */
    public void handleMessage(@NonNull Message msg) {
    }

Callback的上面已經(jīng)寫(xiě)了就不說(shuō)了号坡。

2.2 Message源碼分析

Message是消息傳遞的載體,可以理解成一個(gè)數(shù)據(jù)mode一樣,下面來(lái)分析一下它的重要屬性與重要方法,
重要屬性梯醒,常用的傳輸數(shù)據(jù)宽堆,比如arg,data茸习,what畜隶,等我就不做說(shuō)明了

    //每個(gè)Message持有發(fā)送Handler的引用,哪來(lái)干什么呢号胚?當(dāng)然是調(diào)用handler.dispatch來(lái)處理消息了
    @UnsupportedAppUsage
    /*package*/ Handler target;
    //上節(jié)講了籽慢,用于將callBack變成Message
    @UnsupportedAppUsage
    /*package*/ Runnable callback;
    //這里next就代表一個(gè)鏈表,每個(gè)對(duì)象的next則指向它的下一個(gè)猫胁,當(dāng)用于回收池時(shí)箱亿,next就指向下一個(gè)回收對(duì)象
    // 當(dāng)用于MessageQueue,就指向下一個(gè)需要處理的message弃秆。
    // sometimes we store linked lists of these things
    @UnsupportedAppUsage
    /*package*/ Message next;


    /**
     * @hide 資源池的對(duì)象鎖
     */
    public static final Object sPoolSync = new Object();
    //Message 池子
    private static Message sPool;
    //當(dāng)前池子有的message數(shù)量
    private static int sPoolSize = 0;
    //池子最大值
    private static final int MAX_POOL_SIZE = 50;
    /**
     * 回收Message是否進(jìn)行安全檢查极景,默認(rèn)為真
     */
    private static boolean gCheckRecycle = true;

重要方法

得到一個(gè)Message對(duì)象,其他幾種方法都是調(diào)用這個(gè)方法得到message對(duì)象驾茴,并對(duì)Handler,callback氢卡,obj等屬性賦值锈至,就不說(shuō)明。理解Mesage回收池是一個(gè)比較重要的地方译秦,其中next的妙用峡捡,牛逼。

    /**
     * Return a new Message instance from the global pool. Allows us to
     * avoid allocating new objects in many cases.
     * 返回一個(gè)Message對(duì)象筑悴,從回收池中
     */
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {//回收池不為空
                Message m = sPool; //spool對(duì)象給m
                sPool = m.next;//spool的next變?yōu)殒湵淼谝粋€(gè)位置
                m.next = null;//m對(duì)象next置空
                m.flags = 0; // clear in-use flag
                sPoolSize--; //線程池-1
                return m;//返回message對(duì)象
            }
        }
        return new Message();
    }

回收一個(gè)Message對(duì)象到回收池

/**
     * 回收消息们拙,當(dāng)回收一個(gè)正在inUse的Message默認(rèn)拋異常,gCheckRecycle默認(rèn)為ture阁吝,5.0以前默認(rèn)為false砚婆,以后默認(rèn)為true,安全第一呀
     * Return a Message instance to the global pool.
     * <p>
     * You MUST NOT touch the Message after calling this function because it has
     * effectively been freed.  It is an error to recycle a message that is currently
     * enqueued or that is in the process of being delivered to a Handler.
     * </p>
     *
     */
    public void recycle() {
        if (isInUse()) {
            if (gCheckRecycle) {
                throw new IllegalStateException("This message cannot be recycled because it "
                        + "is still in use.");
            }
            return;
        }
        recycleUnchecked();
    }

/**
     * 不安全的回收Message方法突勇,可能會(huì)回收一個(gè)處于in-use的Message
     * Recycles a Message that may be in-use.
     * Used internally by the MessageQueue and Looper when disposing of queued Messages.
     */
    @UnsupportedAppUsage
    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.恢復(fù)相關(guān)屬性到默認(rèn)值
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = UID_NONE;
        workSourceUid = UID_NONE;
        when = 0;
        target = null;
        callback = null;
        data = null;
        //這里說(shuō)明一下装盯,在完成一次回收后,sPool就變成剛剛回收的Message對(duì)象甲馋,而next就指向上一次的回收對(duì)象
        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {//回收池中數(shù)量小于Max才進(jìn)行回收操作
                next = sPool;//將當(dāng)前線程池的Message對(duì)象賦值給next
                sPool = this;//將需要回收的這個(gè)對(duì)象引用給回收池--至此回收完成埂奈,回收池?cái)?shù)量+1,
                sPoolSize++;
            }
        }
    }

2.3 MessageQueue源碼解析

在Handler 中我們分析到sendMesage 最后調(diào)用到MessageQueue的enqueueMessage方法定躏,那我們從這個(gè)方法開(kāi)始分析账磺。

 /**
     * 向messageQueue message
     *
     * @param msg  加入的消息
     * @param when 消息發(fā)送的時(shí)間
     * @return 是否加入成功
     */
    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {//說(shuō)明必須要有target對(duì)象才能處理消息
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {//message正在處理芹敌,重復(fù)發(fā)送某個(gè)Message對(duì)象可能會(huì)出現(xiàn)這個(gè)問(wèn)題
            throw new IllegalStateException(msg + " This message is already in use.");
        }
,
        synchronized (this) {
            if (mQuitting) {//正在退出垮抗,將該msg回收氏捞,加入消息失敗
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse();//標(biāo)記當(dāng)前msg正在使用中
            msg.when = when;//賦值消息處理時(shí)間
            Message p = mMessages;//這里的mMessage就是待處理的一個(gè)鏈表隊(duì)列,
            boolean needWake;
            //當(dāng)p為空 代表啥借宵?代表該msg是MessageQueue隊(duì)列收到的第一個(gè)消息幌衣,它還是空的,啥也沒(méi)有
            //when==0 代表啥壤玫?從前面可知 當(dāng)uptimeMillis為0,即現(xiàn)在的when豁护,表示要把它放在隊(duì)列最前面,
            //when<p.when  嘛意思? 意思很簡(jiǎn)單欲间,我這個(gè)msg的執(zhí)行時(shí)間比你p列表最前面的還要早楚里,應(yīng)該讓我最先執(zhí)行
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                //所以if成立的執(zhí)行結(jié)果就很明顯了,1.將msg對(duì)象放在鏈表的首位over~
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;//是否需要喚醒
            } else {//執(zhí)行這個(gè)Block啥意思猎贴?就是msg肯定不在鏈表前面了該給他找個(gè)合適的位置了,排序操作班缎,排序條件when,
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (; ; ) {//循環(huán)操作
                    prev = p;//鏈表交給prev
                    p = p.next;//鏈表的老二變老大
                    if (p == null || when < p.when) {//p==?啥意思她渴,就是老二沒(méi)有达址,循環(huán)結(jié)束 when<p.when啥意思?新的老二已經(jīng)誕生了循環(huán)結(jié)束趁耗,哈哈
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                //msg可能是老二沉唠,老三。苛败。满葛。總之他去了該去的地方罢屈,一路走好~~~至此加入message完成
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

MessageQueue既然有了加入消息的方法嘀韧,獲取當(dāng)前待處理的消息就必不可少了,接下來(lái)讓我們看看MessageQueue的next方法如何提取消息
不看不知道缠捌,一看嚇一跳锄贷,next方法比enqueueMessage方法復(fù)雜多了.難道不是
Message message=mMessages;
mMessages=mMessages.next;
這么簡(jiǎn)單嗎,哈哈

 @UnsupportedAppUsage
    Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        final long ptr = mPtr;//native消息計(jì)數(shù)
        if (ptr == 0) {
            return null; //沒(méi)有消息
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (; ; ) {//死循環(huán)
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
            nativePollOnce(ptr, nextPollTimeoutMillis);
            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {//當(dāng)target為null曼月,查詢(xún)異步消息
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.找到異步消息肃叶,退出循環(huán)
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());//遍歷msg獲取到符合條件的異步消息
                }
                if (msg != null) {
                    if (now < msg.when) {//還沒(méi)到消息發(fā)送時(shí)間,計(jì)算下一次執(zhí)行的時(shí)間
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {//到時(shí)間了十嘿,找到了msg并返回
                        // Got a message.
                        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 {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {//正在退出因惭,返回null
                    dispose();
                    return null;
                }

                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // Run the idle handlers.
            // We only ever reach this code block during the first iteration.
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler

                boolean keep = false;
                try {
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // Reset the idle handler count to 0 so we do not run them again.
            pendingIdleHandlerCount = 0;

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;
        }
    }

2.4Looper源碼解析

Looper通過(guò)調(diào)用MessageQueue 的next方法獲取到可以處理的message,并調(diào)用message.target.dispatch方法分發(fā)消息,完成消息處理最后的流程绩衷。接下來(lái)看看Looper的重要屬性蹦魔,與方法激率。

重要屬性

    // sThreadLocal.get() will return null unless you've called prepare().
    //ThreadLocal簡(jiǎn)稱(chēng)TLS線程本地存儲(chǔ)區(qū)域,用于線程存儲(chǔ)信息勿决,通過(guò)get乒躺,set方法,這里被用來(lái)存儲(chǔ)looper對(duì)象
    @UnsupportedAppUsage
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    /**
     * 主線程looperd對(duì)象
     */
    @UnsupportedAppUsage
    private static Looper sMainLooper;  // guarded by Looper.class
    
    private static Observer sObserver;
    /**
     * 消息隊(duì)列低缩,用于獲取笑嘻嘻
     */
    @UnsupportedAppUsage
    final MessageQueue mQueue;
    /**
     * looper所在的線程
     */
    final Thread mThread;

重要方法
Looper的創(chuàng)建

    /**
     * Looper初始化
     * @param quitAllowed
     */
    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {//一個(gè)線程只有一個(gè)Looper
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));//創(chuàng)建Looper并存儲(chǔ)到TLS
    }

Looper構(gòu)造函數(shù)

    private Looper(boolean quitAllowed) {//創(chuàng)建Pooper
        mQueue = new MessageQueue(quitAllowed);//創(chuàng)建MessageQueue Looper是否允許退出
        mThread = Thread.currentThread();//當(dāng)前線程
    }

獲取存儲(chǔ)的looper對(duì)象

 /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     * 從TLS中獲取Looper對(duì)象
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

Loop方法循環(huán)拾取MessageQueue的Message,這里只取了關(guān)鍵代碼部分嘉冒,其他關(guān)于日志log的進(jìn)行了刪減

 for (; ; ) {//又見(jiàn)死循環(huán)
            Message msg = queue.next(); // might block  從Messagequeue中獲取message
            if (msg == null) {//沒(méi)有可以處理的消息,返回
                // No message indicates that the message queue is quitting.
                return;
            }
            msg.target.dispatchMessage(msg);//分發(fā)消息
 
            msg.recycleUnchecked();//消息分發(fā)完成咆繁,進(jìn)行回收處理
        }
    }

Looper的queit方法

  public void quit() {
        mQueue.quit(false);//安全退出
    }
   public void quitSafely() {
        mQueue.quit(true);不安全退出
    }

MessageQueue的退出方法

    //
    void quit(boolean safe) {
        //當(dāng)mQuitAllowed為false表示不能退出
        if (!mQuitAllowed) {
            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);
        }
    }

總結(jié):Handler(sendMessage)message=========>MessageQueue======>Loop(取出消息)=====》Handler (dispatchMessage)就分析完畢

到這里Java層的Handler的消息機(jī)制差不多就清晰了。下面貼一張關(guān)系圖便于理解玩般。


Handler機(jī)制
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末银觅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子坏为,更是在濱河造成了極大的恐慌究驴,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件匀伏,死亡現(xiàn)場(chǎng)離奇詭異洒忧,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)够颠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)熙侍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人摧找,你說(shuō)我怎么就攤上這事±喂瑁” “怎么了蹬耘?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)减余。 經(jīng)常有香客問(wèn)我综苔,道長(zhǎng),這世上最難降的妖魔是什么位岔? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任如筛,我火速辦了婚禮,結(jié)果婚禮上抒抬,老公的妹妹穿的比我還像新娘杨刨。我一直安慰自己,他們只是感情好擦剑,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布妖胀。 她就那樣靜靜地躺著芥颈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赚抡。 梳的紋絲不亂的頭發(fā)上爬坑,一...
    開(kāi)封第一講書(shū)人閱讀 51,692評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音涂臣,去河邊找鬼盾计。 笑死,一個(gè)胖子當(dāng)著我的面吹牛赁遗,可吹牛的內(nèi)容都是我干的署辉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼吼和,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼涨薪!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起炫乓,我...
    開(kāi)封第一講書(shū)人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤刚夺,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后末捣,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體侠姑,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年箩做,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了莽红。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡邦邦,死狀恐怖安吁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情燃辖,我是刑警寧澤鬼店,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站黔龟,受9級(jí)特大地震影響妇智,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜氏身,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一巍棱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蛋欣,春花似錦航徙、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)倒得。三九已至,卻和暖如春夭禽,著一層夾襖步出監(jiān)牢的瞬間霞掺,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工讹躯, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留菩彬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓潮梯,卻偏偏與公主長(zhǎng)得像骗灶,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子秉馏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355