MessageQueue源碼學(xué)習(xí)

官方注釋:
MessageQueue是保存消息列表的低級(jí)別類,消息由Looper對(duì)象派發(fā)俺亮。消息并不是直接添加到MessageQueue中的,而是通過(guò)與Looper對(duì)象關(guān)聯(lián)的MessageQueue.IdleHandler對(duì)象添加十偶。
調(diào)用Looper.myQueue方法可以獲取當(dāng)前線MessageQueue转捕。

參數(shù)解釋:
private int mPtr; // 使用本機(jī)code

表示MessageQueue是否允許退出
mQuitAllowed    

存放IdleHandler對(duì)象的一個(gè)ArrayList
private final ArrayList<IdleHandler> mIdleHandlers = new 

ArrayList<IdleHandler>();

一個(gè)IdleHandler數(shù)組
private IdleHandler[] mPendingIdleHandlers;

判斷Thread是否退出
private boolean mQuitting;

是否被阻塞
private boolean mBlocked;

下一個(gè)障礙記號(hào)?耗式?胁住?
private int mNextBarrierToken;

jni調(diào)底層的c
private native static long nativeInit();
private native static void nativeDestroy(long ptr);
private native static void nativePollOnce(long ptr, int timeoutMillis);
private native static void nativeWake(long ptr);
private native static boolean nativeIsIdling(long ptr);

IdleHandler在Handler空閑時(shí)執(zhí)行,好處在于可以不用指定一個(gè)將來(lái)時(shí)間刊咳,只要線程空閑了彪见,就可以執(zhí)行它指定的操作。比較適合那種需要在將來(lái)執(zhí)行操作娱挨,但是又不知道需要指定多少延遲時(shí)間的操作
public static interface IdleHandler {
boolean queueIdle();
}

添加和刪除IdleHandler的方法
addIdleHandler(IdleHandler handler)
removeIdleHandler(IdleHandler handler)

創(chuàng)建消息隊(duì)列
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();//通過(guò)native方法初始化消息隊(duì)列
}

對(duì)象銷毀時(shí)余指,該方法finalize()被自動(dòng)調(diào)用。主要是通過(guò)native方法銷毀前創(chuàng)建的nativeMessageQueue方法
protected void finalize() throws Throwable {
try {
dispose();
} finally {
super.finalize();
}
}

private void dispose() {
    if (mPtr != 0) {
        nativeDestroy(mPtr);
        mPtr = 0;
    }
}

//next方法會(huì)取出下一個(gè)Message(從頭部弱伟印)酵镜,如果沒(méi)有Message可以處理,就可以處理下IdleHandler

Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}

    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            //等待刷新
            Binder.flushPendingCommands();
        }

//調(diào)用native層進(jìn)行消息標(biāo)示 0立即返回 -1 等待
//一:是當(dāng)消息隊(duì)列中沒(méi)有消息時(shí)線程進(jìn)入等待柴钻,二:消息指定了時(shí)間淮韭,而現(xiàn)在還沒(méi)有到這個(gè)時(shí)間
nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            // 試圖獲取下一條消息。如果發(fā)現(xiàn)返回贴届。
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            //尋找下一個(gè)異步消息隊(duì)列中
            if (msg != null && msg.target == null) {
                do {
                    prevMsg = msg;
                    msg = msg.next;

//(flags & FLAG_ASYNCHRONOUS) != 0; //FLAG_ASYNCHRONOUS = 1 << 1;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// 下一個(gè)消息沒(méi)有準(zhǔn)備好靠粪。設(shè)置一個(gè)超時(shí)時(shí)間作為下次休眠的依據(jù)
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 (false) Log.v("MessageQueue", "Returning message: " + msg);
return msg;
}
} else {
// 沒(méi)有更多信息
nextPollTimeoutMillis = -1;
}

            // 如果還有消息沒(méi)處理,交給底層處理
            if (mQuitting) {
                dispose();
                return null;
            }

            //?????
            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("MessageQueue", "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;
    }
}

總結(jié):
每個(gè)Message之間是串連在一起的占键,Message只要知道自己的前面一個(gè)Message和后面一個(gè)Message就可以了,Message之間的排序通過(guò)用時(shí)間戳來(lái)排序,時(shí)間戳小的排在前面绍些。

再配合上handler對(duì)于消息的取出捞慌,第一個(gè)Message的時(shí)間到了耀鸦,就取隊(duì)列的第一個(gè)Message柬批,取完之后啸澡,將第一個(gè)Message置空,這樣第二個(gè)Message就排在第一個(gè)了氮帐,依此類推嗅虏。

遺留問(wèn)題:
1.pendingIdleHandlerCount < 0 完后為什么還有一個(gè)
pendingIdleHandlerCount <= 0 的判斷,為什么這樣寫(xiě)上沐?
2.if (false) Log.v 這個(gè)false的寫(xiě)法奇怪皮服?
3.為什么一定要用jni來(lái)處理?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末参咙,一起剝皮案震驚了整個(gè)濱河市龄广,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蕴侧,老刑警劉巖择同,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異净宵,居然都是意外死亡敲才,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門择葡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)紧武,“玉大人,你說(shuō)我怎么就攤上這事敏储∽栊牵” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵已添,是天一觀的道長(zhǎng)迫横。 經(jīng)常有香客問(wèn)我,道長(zhǎng)酝碳,這世上最難降的妖魔是什么矾踱? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮疏哗,結(jié)果婚禮上呛讲,老公的妹妹穿的比我還像新娘。我一直安慰自己返奉,他們只是感情好贝搁,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著芽偏,像睡著了一般雷逆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上污尉,一...
    開(kāi)封第一講書(shū)人閱讀 51,763評(píng)論 1 307
  • 那天膀哲,我揣著相機(jī)與錄音往产,去河邊找鬼。 笑死某宪,一個(gè)胖子當(dāng)著我的面吹牛仿村,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播兴喂,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蔼囊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了衣迷?” 一聲冷哼從身側(cè)響起畏鼓,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎壶谒,沒(méi)想到半個(gè)月后滴肿,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡佃迄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年泼差,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呵俏。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡堆缘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出普碎,到底是詐尸還是另有隱情吼肥,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布麻车,位于F島的核電站缀皱,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏动猬。R本人自食惡果不足惜啤斗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赁咙。 院中可真熱鬧钮莲,春花似錦、人聲如沸彼水。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)凤覆。三九已至链瓦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間盯桦,已是汗流浹背慈俯。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工渤刃, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人肥卡。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像事镣,于是被迫代替她去往敵國(guó)和親步鉴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

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