欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Android消息機(jī)制完整的執(zhí)行流程

 更新時(shí)間:2022年10月11日 15:32:46   作者:長(zhǎng)安皈故里  
經(jīng)過(guò)前面幾篇文章的鋪墊,介紹了Hanlder、Message等類相關(guān)使用,分析了其與Looper、MessageQueue的部分源碼,本篇文章主要是集中梳理Android整個(gè)消息機(jī)制執(zhí)行的完整流程,需要的可以參考一下

從Handler.post()說(shuō)起

Handler.post()是用來(lái)發(fā)送消息的,我們看下Handler源碼的處理:

public final boolean post(@NonNull Runnable r) {
   return sendMessageDelayed(getPostMessage(r), 0);
}

首先會(huì)調(diào)用到getPostMessage()方法將Runnable封裝成一條Message,然后緊接著調(diào)用sendMessageDelayed()方法:

public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

這里我們介紹下sendMessageDelayed()的第二個(gè)參數(shù)delayMillis,這個(gè)表示消息延時(shí)執(zhí)行的時(shí)間,而post()方法本身代表著非延遲執(zhí)行,所以這里delayMillis的值為0.

而如果是我們另一個(gè)常用的函數(shù)postDelay(),這里的delayMillis的值就是傳入的延遲執(zhí)行的時(shí)間

繼續(xù)往下走,會(huì)調(diào)用到Handler.sendMessageAtTime()方法:

public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    //...
    return enqueueMessage(queue, msg, uptimeMillis);
}

獲取到Looper對(duì)應(yīng)的消息隊(duì)列MessageQueue,繼續(xù)往下走,作為參數(shù)傳給enqueueMessage()方法,這個(gè)方法主要是對(duì)上面封裝的Message進(jìn)行填充:

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

比如將Message被負(fù)責(zé)分發(fā)的target賦值成當(dāng)前Handler對(duì)象,然后根據(jù)是否為異步Handler來(lái)決定是否給Message添加異步標(biāo)識(shí)。

MessageQueue.enqueueMessage()添加消息至隊(duì)列中

boolean enqueueMessage(Message msg, long when) {
    //...
    synchronized (this) {
        //...
        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        //1.
        if (p == null || when == 0 || when < p.when) {
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            //2.
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p;
            prev.next = msg;
        }
        //3.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

這個(gè)方法的使用很明確,就是將Message添加到消息隊(duì)列中,下來(lái)我們主要講解這個(gè)方法的三個(gè)核心點(diǎn),對(duì)應(yīng)上面的注釋標(biāo)識(shí):

1.如果當(dāng)前消息隊(duì)列本來(lái)為null、消息執(zhí)行的時(shí)間戳為0、消息執(zhí)行的時(shí)間小于消息隊(duì)列隊(duì)頭消息的執(zhí)行時(shí)間,只要滿足上面三個(gè)條件之一,直接將該條Message添加到消息隊(duì)列隊(duì)頭;

這里說(shuō)下消息執(zhí)行的時(shí)間戳什么時(shí)候會(huì)為0,就是調(diào)用Handler.sendMessageAtFrontOfQueue()這個(gè)方法,就會(huì)觸發(fā)將當(dāng)前發(fā)送的Message添加到消息隊(duì)列隊(duì)頭。

2.如果上面的三個(gè)條件都不滿足,就遍歷消息隊(duì)列,比較將要發(fā)送的消息和消息隊(duì)列的消息執(zhí)行時(shí)間戳when,選擇適當(dāng)?shù)奈恢貌迦耄?/p>

3.判斷是否需要喚醒當(dāng)前主線程,開(kāi)始從消息隊(duì)列獲取消息進(jìn)行執(zhí)行;

Looper.loop()分發(fā)消息

這個(gè)方法會(huì)開(kāi)啟一個(gè)for(;;)循環(huán),不斷的從消息隊(duì)列中獲取消息分發(fā)執(zhí)行,沒(méi)有消息時(shí)會(huì)阻塞主線程進(jìn)行休眠,讓出CPU執(zhí)行權(quán)。

for(;;)循環(huán)會(huì)不斷的調(diào)用Looper.loopOnce(),開(kāi)始真正的消息獲取和分發(fā)執(zhí)行:

private static boolean loopOnce(final Looper me,
        final long ident, final int thresholdOverride) {
    Message msg = me.mQueue.next(); // might block
    if (msg == null) {
        return false;
    }
    try {
        msg.target.dispatchMessage(msg);
    }
    msg.recycleUnchecked();
    return true;
}

上面是經(jīng)過(guò)簡(jiǎn)化的代碼,首先調(diào)用MessageQueue.next()從消息隊(duì)列中獲取消息,然后調(diào)用關(guān)鍵方法msg.target.dispatchMessage(msg)開(kāi)始消息的分發(fā)執(zhí)行,這個(gè)方法之前的文章有進(jìn)行介紹,這里就不再過(guò)多介紹了。

接下來(lái)我們看下MessageQueue.next()如何獲取消息的。

MessageQueue.next()獲取消息

Message next() {
    //...
    for (;;) {
        //1.休眠主線程
        nativePollOnce(ptr, nextPollTimeoutMillis);
        synchronized (this) {
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            //2.獲取異步消息
            if (msg != null && msg.target == null) {
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            //3.獲取普通消息
            if (msg != null) {
                if (now < msg.when) {
                    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;
                    msg.markInUse();
                    return msg;
                }
            } else {
                nextPollTimeoutMillis = -1;
            }
            
            //...
            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }
        //4.執(zhí)行Idle消息
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null;

            boolean keep = idler.queueIdle();
            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }
        //...
    }
}
  • 如果當(dāng)前消息隊(duì)列中沒(méi)有消息或者還沒(méi)到下一條消息的執(zhí)行時(shí)間,就調(diào)用nativePollOnce()方法休眠主線程,讓出CPU執(zhí)行權(quán);
  • 如果Message的target為null,就代表是一個(gè)消息屏障消息,之后就只能從消息隊(duì)列獲取異步消息了,如果不存在,就嘗試執(zhí)行Idle消息;
  • 如果不存在消息屏障,則就從消息隊(duì)列中正常嘗試獲取Message,如果不存在,就嘗試執(zhí)行Idle消息;
  • 執(zhí)行Idle消息,只有在主線程空閑(當(dāng)前消息隊(duì)列中沒(méi)有消息或者還沒(méi)到下一條消息的執(zhí)行時(shí)間)的情況下才會(huì)去嘗試執(zhí)行Idle消息,這種類型的消息非常有用,具體的可以參考我之前寫(xiě)的文章:IdleHandler基本使用及應(yīng)用案例分析

總結(jié)

本篇文章主要是詳細(xì)分析了Android消息機(jī)制的整個(gè)執(zhí)行流程(不包括native層),最核心的就是HandlerLooper、MessageQueue、Message四個(gè)類及構(gòu)成的關(guān)聯(lián)。

到此這篇關(guān)于詳解Android消息機(jī)制完整的執(zhí)行流程的文章就介紹到這了,更多相關(guān)Android消息機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論