Handler原理講解

首先我們看下Handler.sendMessage開始,可以看到在Handler中都調(diào)用了sendMessageAtTime:

public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue; // A
        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);
    }

在A處,獲取的是mQueue,那么這個mQueue是什么呢?我們查找下。

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

我們可以看到mQueue是在Looper中獲取到的。那么Looper是怎么來的,這個Looper中的mQueue到底是什么東西呢?我們接著看下Looper中的源碼:

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    ...
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

因為使用static修飾,所以sThreadLocal在內(nèi)存中只會有一份。接著看下sThreadLocal.get()中的邏輯:

    public T get() {
        Thread t = Thread.currentThread(); // A
        ThreadLocalMap map = getMap(t); // B
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this); // C
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
    ...
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

        ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
            table = new Entry[INITIAL_CAPACITY];
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
        }

A處獲取當(dāng)前線程;B處看,每個線程都會維護一個ThreadLocalMap類型的threadLocals成員變量。
** 注意 **: 總匯一下,一個線程只有一個ThreadLocalMap類型的變量threadLocals。Looper.myLoop()是調(diào)用靜態(tài)變量ThreadLocal的get方法。get方法中是獲取當(dāng)前線程的threadLocals中以ThreadLocal為索引的value即當(dāng)前線程的Looper。set方法是在Looper的prepare中設(shè)置的。
回到

public Handler(@Nullable Callback callback, boolean async) {
    ...
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
           "Can't create handler inside thread " + Thread.currentThread()
            + " that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue; // B
    ...
}

代碼B注釋處。

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

一個Looper會有一個MessageQueue。這時候我們就清楚mQueue到底是什么了。接著看代碼。

public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue; // A
        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); // B
    }

B處是將消息加入隊列。

    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

接著看下MessageQueue中代碼

   boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }

        synchronized (this) {
            if (msg.isInUse()) {
                throw new IllegalStateException(msg + " This message is already in use.");
            }

            if (mQuitting) {
                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();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // 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 (;;) {
                    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;
            }

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

可以看出來MessageQueue中維護的是Message的鏈表。Message就是一個node結(jié)構(gòu)。
到這里sendMessage邏輯就完了。
但還有一點要補充的,消息進(jìn)隊列后怎么執(zhí)行的呢?
線程創(chuàng)建的時候會調(diào)用Looper的prepare和loop方法。prepare給當(dāng)前線程threadLocals保存了Looper。loop()方法則是不停循環(huán)處理MessageQueue中的消息。

Looper中有:

  • ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
  • final MessageQueue mQueue;
    Thread中有:
  • ThreadLocalMap類型的成員變量threadLocals.
    MessageQueue:
  • 維護了Message的鏈表
?著作權(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ù)。

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

  • Handler切換線程原理解析 寫在前面:本文的目的是想將Handler、Looper和Thread之間綁定的原理...
    tinyvampirepudg閱讀 3,020評論 0 5
  • 一、google為什么設(shè)計這套機制 主要是為了解決在非UI線程中更新UI組件比較麻煩的問題。 二、google如何...
    可愛的肥臉閱讀 783評論 6 6
  • 在Android系統(tǒng)中,Handler機制應(yīng)用較廣,尤其是在App層面,基本每個App都會用到。使用的場景主要是向...
    路路人王閱讀 867評論 0 49
  • 一、前言 在 Android 開發(fā)中,handler 機制的使用幾乎隨處可見,作為面試中的???,我們真的了...
    阿西糖閱讀 819評論 0 2
  • 久違的晴天,家長會。 家長大會開好到教室時,離放學(xué)已經(jīng)沒多少時間了。班主任說已經(jīng)安排了三個家長分享經(jīng)驗。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,809評論 16 22

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