日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無先后,達(dá)者為師

網(wǎng)站首頁 編程語言 正文

Android移除Message的方法分享_Android

作者:長安皈故里 ? 更新時間: 2022-11-23 編程語言

退出Looper循環(huán)移除Message的兩種方式

大家都知道,消息機(jī)制在Android系統(tǒng)運(yùn)行中扮演著重要的角色,通過消息發(fā)送、添加消息隊(duì)列、分發(fā)等一整個流程驅(qū)動Android的運(yùn)行。

主線程是在ActivityThread.main()中調(diào)用了Looper.loop(),開啟消息循環(huán)遍歷執(zhí)行的,這個消息循環(huán)可以退出嗎,接下來我們仔細(xì)研究下;

上源碼:

void quit(boolean safe) {
    //1.不允許退出就拋出異常
    if (!mQuitAllowed) {
        throw new IllegalStateException("Main thread not allowed to quit.");
    }

    synchronized (this) {
        if (mQuitting) {
            return;
        }
        //2.
        mQuitting = true;

        if (safe) {
            //3.安全退出
            removeAllFutureMessagesLocked();
        } else {
            //4.非安全退出
            removeAllMessagesLocked();
        }

        nativeWake(mPtr);
    }
}

1.對于主線程而言,mQuitAllowed的值是false,也就是說主線程的Looper循環(huán)不允許手動調(diào)用quit()退出,否則就拋出異常;

2.將退出標(biāo)識mQuitting置為true,這樣當(dāng)從消息隊(duì)列中取消息時,會先判斷下這個標(biāo)識mQuitting是否為true,是就會經(jīng)過調(diào)用鏈一步步退出Looper消息循環(huán);

3.安全的退出Looper開啟的消息循環(huán),深入下removeAllFutureMessagesLocked()看下:

private void removeAllFutureMessagesLocked() {
    final long now = SystemClock.uptimeMillis();
    Message p = mMessages;
    if (p != null) {
        //1.
        if (p.when > now) {
            removeAllMessagesLocked();
        } else {
            Message n;
            for (;;) {
                n = p.next;
                if (n == null) {
                    return;
                }
                if (n.when > now) {
                    break;
                }
                p = n;
            }
            p.next = null;
            do {
                p = n;
                n = p.next;
                p.recycleUnchecked();
            } while (n != null);
        }
    }
}
  • 首先如果消息隊(duì)列隊(duì)頭的消息的執(zhí)行時間戳when大于當(dāng)前時間,則直接調(diào)用 removeAllMessagesLocked()方法移除所有的消息 ,這個方法之后會講解;
  • 上面條件不滿足,就不斷的遍歷消息隊(duì)列,直到找出執(zhí)行時間戳大于當(dāng)前時間的消息,然后通過do-while()循環(huán),將該消息及之后的消息全部進(jìn)行回收處理,放入到我們之前講解的對象池;

4.非安全的退出是直接調(diào)用了removeAllMessagesLocked()方法,我們深入看下:

private void removeAllMessagesLocked() {
    Message p = mMessages;
    while (p != null) {
        Message n = p.next;
        p.recycleUnchecked();
        p = n;
    }
    mMessages = null;
}

可以看到這種移除方法大殺特殺,不會去比較消息執(zhí)行的時間戳啥的,直接全部干翻回收到消息對象池,簡單粗暴。

這里對于非安全和安全退出Looper循環(huán)做個總結(jié):

安全退出Looper循環(huán)只會移除回收大于當(dāng)前時間戳的消息,而不大于當(dāng)前時間戳的消息都可以保證正常執(zhí)行;而非安全的退出比較粗暴,直接清空回收整個消息隊(duì)列。這兩種情況大家根據(jù)需要選擇性的使用。

removeXXXMessages()移除指定的消息

可以看到移除消息的方法一大堆,比如通過指定Messagewhatobjcallback等信息移除指定Message,這里我們就以removeCallbacksAndMessages()舉例。

removeCallbacksAndMessages()方法大家應(yīng)該很梳理,是我們在某個界面中使用Handler發(fā)送消息時,避免發(fā)生內(nèi)存泄漏的一種方式,接下來我們深入分析下:

void removeCallbacksAndMessages(Handler h, Object object) {
    //...
    synchronized (this) {
        Message p = mMessages;
        //1.從頭移除消息
        while (p != null && p.target == h
                && (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            p.recycleUnchecked();
            p = n;
        }

        //2. 從中間移除消息
        while (p != null) {
            Message n = p.next;
            if (n != null) {
                if (n.target == h && (object == null || n.obj == object)) {
                    Message nn = n.next;
                    n.recycleUnchecked();
                    p.next = nn;
                    continue;
                }
            }
            p = n;
        }
    }
}

如果這個方法傳入的object不為null,就會移除指定的Message,如果指定為null,就會移除傳入的Handler發(fā)送的所有消息。

上面的源碼中可以看到,移除Message分為兩個部分,為什么要這么做呢?

假設(shè)消息隊(duì)列中存在下面一系列消息集合:

如果Message1滿足移除條件,那么直接回收這條消息,并將消息隊(duì)列的隊(duì)頭指針指向下一個消息即可mMessages = mMessages.next,對應(yīng)上面源碼中前半部分移除消息的邏輯。

但假設(shè)Message1不滿足移除條件,Message2滿足移除條件,這樣移除就不是直接將消息隊(duì)列的隊(duì)頭指針指向next即下一個Message就能簡單解決的。

正確的做法是:先要保存Message1,然后通過Message2.next獲取到Message3的引用保存起來,最后將Message1.next指向上面保存的Message3引用。這部分就對應(yīng)上面源碼中后半部分移除消息的邏輯。

總結(jié)

本篇文章主要是對MessageQueue提供的各種移除Message的方法做了一個簡單的介紹,方法很多主要分為兩種:移除指定標(biāo)識的Handler發(fā)送的Message和移除所有Handler發(fā)送的Message

原文鏈接:https://juejin.cn/post/7153056511831310366

欄目分類
最近更新