Android 消息機(jī)制系列(3)——終止消息循環(huán)

本文主要內(nèi)容:
從Looper源碼的角度,分析如何終止消息循環(huán)渣淤,以及終止消息循環(huán)的兩種方式的不同赏寇。

一、Looper終止消息循環(huán)
Looper終止消息循環(huán)有兩種方法价认,quit()和quitSafely()

Looper的quitSafely()方法:

public void quitSafely() {
    mQueue.quit(true);
}

Looper的quit()方法:

public void quit() {
    mQueue.quit(false);
}

二者共同調(diào)用了MessageQueue的quit(boolean safe)方法:

void quit(boolean safe) {
    if (!mQuitAllowed) {
        throw new IllegalStateException("Main thread not allowed to quit.");
    }

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

        if (safe) {
            removeAllFutureMessagesLocked();
        } else {
            removeAllMessagesLocked();
        }

        // We can assume mPtr != 0 because mQuitting was previously false.
        nativeWake(mPtr);
    }
}

兩者的區(qū)別就在于其中的這幾句:

        if (safe) {
            removeAllFutureMessagesLocked(); //清空延遲消息
        } else {
            removeAllMessagesLocked(); //清空所有消息
        }

removeAllMessagesLocked方法嗅定,該方法的作用是把MessageQueue消息池中所有的消息全部清空,無論是延遲消息還是非延遲消息用踩。(延遲消息是指通過sendMessageDelayed或通過postDelayed等方法發(fā)送的需要延遲執(zhí)行的消息)

removeAllFutureMessagesLocked方法渠退,只會清空MessageQueue消息池中所有的延遲消息,并將消息池中所有的非延遲消息派發(fā)出去讓Handler去處理脐彩,quitSafely相比于quit方法安全之處在于清空消息之前會派發(fā)所有的非延遲消息碎乃。

private void removeAllFutureMessagesLocked() {
    final long now = SystemClock.uptimeMillis();
    Message p = mMessages;
    if (p != null) {
        if (p.when > now) { //延遲執(zhí)行的消息
            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);
        }
    }
}

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

最后,當(dāng)Looper.loop繼續(xù)從MessageQueue中獲取消息時惠奸,發(fā)現(xiàn)獲取的是空荠锭,消息循環(huán)就終結(jié)了。這時候再通過Handler調(diào)用sendMessage或post等方法發(fā)送消息時均返回false晨川,表示消息沒有成功放入消息隊列MessageQueue中证九,因為消息隊列已經(jīng)退出了删豺,具體分析見下面:

MessageQueue中插入消息的代碼如下:

boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
    if (msg.isInUse()) {
        throw new IllegalStateException(msg + " This message is already in use.");
    }

    synchronized (this) {
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w("MessageQueue", 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;
}

其中這一句:

synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
msg.recycle();
return false;
}

mQuitting表示已經(jīng)退出。這個時候無法插入消息愧怜,返回false呀页。

參考:

Looper源代碼:

MessageQueue源代碼:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/os/MessageQueue.java#MessageQueue.quit%28boolean%29

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市拥坛,隨后出現(xiàn)的幾起案子蓬蝶,更是在濱河造成了極大的恐慌,老刑警劉巖猜惋,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丸氛,死亡現(xiàn)場離奇詭異,居然都是意外死亡著摔,警方通過查閱死者的電腦和手機(jī)缓窜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谍咆,“玉大人禾锤,你說我怎么就攤上這事∧〔欤” “怎么了恩掷?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長供嚎。 經(jīng)常有香客問我黄娘,道長,這世上最難降的妖魔是什么克滴? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任逼争,我火速辦了婚禮,結(jié)果婚禮上偿曙,老公的妹妹穿的比我還像新娘氮凝。我一直安慰自己,他們只是感情好望忆,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布罩阵。 她就那樣靜靜地躺著,像睡著了一般启摄。 火紅的嫁衣襯著肌膚如雪稿壁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天歉备,我揣著相機(jī)與錄音傅是,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛喧笔,可吹牛的內(nèi)容都是我干的帽驯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼书闸,長吁一口氣:“原來是場噩夢啊……” “哼尼变!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起浆劲,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤嫌术,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后牌借,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體度气,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年膨报,在試婚紗的時候發(fā)現(xiàn)自己被綠了磷籍。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡丙躏,死狀恐怖择示,靈堂內(nèi)的尸體忽然破棺而出束凑,到底是詐尸還是另有隱情晒旅,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布汪诉,位于F島的核電站废恋,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏扒寄。R本人自食惡果不足惜鱼鼓,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望该编。 院中可真熱鬧迄本,春花似錦、人聲如沸课竣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽于樟。三九已至公条,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間迂曲,已是汗流浹背靶橱。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人关霸。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓传黄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親队寇。 傳聞我的和親對象是個殘疾皇子尝江,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容