Handler機制

消息機制

Java層

1.Looper構(gòu)建了消息隊列MessageQueue
2.Message的成員target關(guān)聯(lián)Handler
3.Handler的成員mQueue關(guān)聯(lián)MessageQueue,成員mLooper關(guān)聯(lián)Looper
4.MessageQueue的成員mMessages關(guān)聯(lián)Message

我們使用Handler時都是先要調(diào)Looper的prepare方法,用于創(chuàng)建Looper和MessageQueue,主線程直接使用Handler是因為在系統(tǒng)已經(jīng)提前給我們創(chuàng)建好了主線程的Looper和MessageQueue
創(chuàng)建App進程后會調(diào)用ActivityThread的main()方法

public static void main(String[] args) {
        ···
        Looper.prepareMainLooper();
        ····
        Looper.loop();
    }

1,創(chuàng)建主線程Looper
2,為主線程Handler賦值
3,Looper.looper啟動循環(huán)

Looper的prepare()

Looper.prepareMainLooper

   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(false)這里的prepare傳的是false,我們自己創(chuàng)建的線程調(diào)用Looper.prepare()傳遞的是true表示可以退出
sMainLooper為全局主線程Looper賦值

public static void prepare() {
    prepare(true);
}
private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {  /* 如果消費者線程已有Looper綁定了,則拋出異常 */
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed)); /* 創(chuàng)建Looper,并綁定到消費者線程 */
}

如果Looper.prepare只能調(diào)用一次,如果多次調(diào)用會拋異常
Looper創(chuàng)建后會存儲在ThreadLocal中,ThreadLocal可以保證線程是唯一的

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

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed); //創(chuàng)建消息隊列
    mThread = Thread.currentThread();       //記錄消費者線程
}

Looper的loop()

public static void loop() {
......
    for (;;) {
        Message msg = queue.next(); //消息隊列出隊得到Message事務(wù)
        if (msg == null) {
            return;
    }
    msg.target.dispatchMessage(msg);//執(zhí)行具體事務(wù)
......
}

MessageQueue.next

 Message next() {
        ···
        for (;;) {
            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) {
                    // 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) {
                        // 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 {
                        // 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) {
                    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;
        }
    }
    

1,nativePollOnce 如果無消息讓消費者線程進入休眠狀態(tài)
2,如果設(shè)置消息屏障取出異步消息
3,檢測消息時間是否到達,到達取出消息,未到達設(shè)置超時時間(目標(biāo)時間 - 當(dāng)前時間)
4,未到達,設(shè)置超時時間,消費者線程進入休眠
5,執(zhí)行IdelHanlder

msg.target.dispatchMessage(msg)

 public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

1,先處理Message CallBack
2,Handler的Callback
3,處理handleMessage

發(fā)送消息

Hanlder.sendMessage(),最終會調(diào)用MessageQueue的enqueueMessage

  boolean enqueueMessage(Message msg, long when) {      
          ···
            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;
    }

1,如果隊列為空直接插入節(jié)點
2,隊列不為空,按時間排序插入
3,線程休眠,插入消息為屏障,插入消息是異步消息并且在第一位,需要喚醒線程

Native層

Looper.prepare()

sp<Looper> Looper::prepare(int opts) {
......
    /* 獲取當(dāng)前消費者線程線程綁定的Looper對象
     * 由于這里首次調(diào)用prepare,還未綁定Looper,因此返回空 
     */
    sp<Looper> looper = Looper::getForThread();
    if (looper == NULL) {
    /* 創(chuàng)建Looper對象(見1.2),然后綁定到當(dāng)前消費者線程中 */
        looper = new Looper(allowNonCallbacks);
        Looper::setForThread(looper);
    }

    return looper;
......
}

在Looper的構(gòu)造函數(shù)
1,創(chuàng)建了eventfd
2,創(chuàng)建epoll文件描述符,用于監(jiān)聽eventfd
Looper.pollOnce
1,消費者線程調(diào)用epoll.wait檢測是否有消息就緒,如果沒有休眠
2,當(dāng)fd就緒,消費者線程被喚醒

MessageQueue
構(gòu)造函數(shù)中會創(chuàng)建Looper
?1.Looper(Java)啟動消息循環(huán),先處理Looper(Native)事務(wù),然后再處理Looper(Java)事務(wù)
?2.Looper(Native)和Looper(Java)均無事務(wù)處理時,消費者線程會進入超時休眠狀態(tài),等待事務(wù)就緒時喚醒

參考
Android P源碼分析之Looper(Native)
Android P源碼分析之Handler(JAVA)

最后編輯于
?著作權(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)容