最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

從Handler.post()說起

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

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

首先會調(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()的第二個參數(shù)delayMillis,這個表示消息延時執(zhí)行的時間,而post()方法本身代表著非延遲執(zhí)行,所以這里delayMillis的值為0.

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

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

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

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

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ā)的target賦值成當前Handler對象,然后根據(jù)是否為異步Handler來決定是否給Message添加異步標識。

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

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

這個方法的使用很明確,就是將Message添加到消息隊列中,下來我們主要講解這個方法的三個核心點,對應(yīng)上面的注釋標識:

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

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

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

3.判斷是否需要喚醒當前主線程,開始從消息隊列獲取消息進行執(zhí)行;

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

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

for(;;)循環(huán)會不斷的調(diào)用Looper.loopOnce(),開始真正的消息獲取和分發(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)過簡化的代碼,首先調(diào)用MessageQueue.next()從消息隊列中獲取消息,然后調(diào)用關(guān)鍵方法msg.target.dispatchMessage(msg)開始消息的分發(fā)執(zhí)行,這個方法之前的文章有進行介紹,這里就不再過多介紹了。

接下來我們看下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);
                }
            }
        }
        //...
    }
}
  • 如果當前消息隊列中沒有消息或者還沒到下一條消息的執(zhí)行時間,就調(diào)用nativePollOnce()方法休眠主線程,讓出CPU執(zhí)行權(quán);
  • 如果Message的target為null,就代表是一個消息屏障消息,之后就只能從消息隊列獲取異步消息了,如果不存在,就嘗試執(zhí)行Idle消息;
  • 如果不存在消息屏障,則就從消息隊列中正常嘗試獲取Message,如果不存在,就嘗試執(zhí)行Idle消息;
  • 執(zhí)行Idle消息,只有在主線程空閑(當前消息隊列中沒有消息或者還沒到下一條消息的執(zhí)行時間)的情況下才會去嘗試執(zhí)行Idle消息,這種類型的消息非常有用,具體的可以參考我之前寫的文章:IdleHandler基本使用及應(yīng)用案例分析

總結(jié)

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

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

相關(guān)文章

  • Android 沉浸式狀態(tài)欄及懸浮效果

    Android 沉浸式狀態(tài)欄及懸浮效果

    這篇文章主要介紹了Android 沉浸式狀態(tài)欄及懸浮效果的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-11-11
  • Android獲取ROOT權(quán)限的實例代碼

    Android獲取ROOT權(quán)限的實例代碼

    這篇文章主要介紹了Android如何獲取ROOT權(quán)限,寫了一個小方法,大家可以在應(yīng)用中檢測ROOT權(quán)限
    2013-11-11
  • android 手機SD卡讀寫操作(以txt文本為例)實現(xiàn)步驟

    android 手機SD卡讀寫操作(以txt文本為例)實現(xiàn)步驟

    要完成SD卡讀寫操作首先對manifest注冊SD卡讀寫權(quán)限其次是創(chuàng)建一個對SD卡中文件讀寫的類寫一個用于檢測讀寫功能的的布局然后就是UI的類了,感興趣的朋友可以參考下,希望可以幫助到你
    2013-02-02
  • Android控件BottomSheet實現(xiàn)底邊彈出選擇列表

    Android控件BottomSheet實現(xiàn)底邊彈出選擇列表

    這篇文章主要介紹了Android控件BottomSheet實現(xiàn)底邊彈出選擇列表,比較常用的選擇條件或跳轉(zhuǎn)方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • 詳解Gradle依賴沖突解決方式

    詳解Gradle依賴沖突解決方式

    這篇文章主要介紹了Gradle依賴沖突解決方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-06
  • Android開發(fā)教程之ContentProvider數(shù)據(jù)存儲

    Android開發(fā)教程之ContentProvider數(shù)據(jù)存儲

    這篇文章主要介紹了Android開發(fā)教程之ContentProvider數(shù)據(jù)存儲的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • Android App中的GridView網(wǎng)格布局使用指南

    Android App中的GridView網(wǎng)格布局使用指南

    GridView布局所實現(xiàn)的就是類似于九宮格的矩陣界面效果,下面整理了Android App中的GridView網(wǎng)格布局使用指南,包括分割線的添加與自定義GridView的實現(xiàn)等技巧,需要的朋友可以參考下
    2016-06-06
  • gradle配置國內(nèi)鏡像的實現(xiàn)

    gradle配置國內(nèi)鏡像的實現(xiàn)

    這篇文章主要介紹了gradle配置國內(nèi)鏡像的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-09-09
  • 4種Android屏幕自適應(yīng)解決方案

    4種Android屏幕自適應(yīng)解決方案

    在開發(fā)android項目的時候,我們常常會考慮這樣的問題:為不同的手機屏幕顯示出最佳的界面,以提升用戶的體驗。本文介紹的是4種Android屏幕自適應(yīng)解決方案,有興趣的可以了解一下。
    2016-10-10
  • 詳解Android studio實現(xiàn)語音轉(zhuǎn)文字功能

    詳解Android studio實現(xiàn)語音轉(zhuǎn)文字功能

    這篇文章主要介紹了如何通過Android studio調(diào)用科大訊飛的語音轉(zhuǎn)文字功能,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下
    2022-03-03

最新評論

会泽县| 工布江达县| 万安县| 芜湖市| 通山县| 中卫市| 德令哈市| 保定市| 博湖县| 康定县| 闽清县| 洛阳市| 启东市| 张家川| 屯昌县| 穆棱市| 鄯善县| 博罗县| 灵璧县| 温宿县| 东阿县| 平安县| 新野县| 平凉市| 长宁县| 西贡区| 绩溪县| 湖北省| 环江| 富裕县| 长葛市| 彭州市| 南宫市| 绥化市| 梧州市| 札达县| 金塔县| 天津市| 霸州市| 万载县| 白城市|