Android:Handler總結(jié)

handler 總結(jié)

handler架構(gòu)包含那幾個(gè)實(shí)體

handler:插入消息到messagequeue
looper:從messagequeue中去消息
messagequeue:存儲(chǔ)消息钾菊,鏈表結(jié)構(gòu)

如何保證每個(gè)線(xiàn)程有一個(gè)looper

使用ThreadLocal<Looper>

如何喚醒messagequeue

插入消息的時(shí)候去喚醒它庭再,底層使用epoll,往epoll寫(xiě)入消息喚醒他黎比。

空閑消息處理器和同步屏障機(jī)制聽(tīng)過(guò)嗎梢杭?

都是優(yōu)先級(jí)相關(guān),同步屏障機(jī)制優(yōu)先級(jí)最高搂橙,空閑消息處理器優(yōu)先級(jí)最低。
https://blog.csdn.net/asdgbc/article/details/79148180
https://blog.csdn.net/kc58236582/article/details/52919904

分析一下去消息的next方法

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

            nativePollOnce(ptr, nextPollTimeoutMillis);  //第一次取消息會(huì)馬上返回橄浓,因?yàn)閚extPollTimeoutMillis=0

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {   //如果沒(méi)有target,就優(yōu)先處理
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {    //消息還沒(méi)到亮航,再等等,這個(gè)等待時(shí)間會(huì)傳到epoll
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        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 (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
               //處理空閑handler
                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;   //沒(méi)有消息匀们,也沒(méi)有空閑的handler缴淋,block住,mBlocked為true的話(huà)泄朴,插入message就會(huì)喚醒epoll
                    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.
            //處理空閑handler
            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(TAG, "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.
             //能到這里重抖,說(shuō)明處理了空閑handler,下次nativepollonce也不需要等待祖灰,直接返回
            nextPollTimeoutMillis = 0;
        }
    }

解析一些epoll函數(shù)

int epoll_create(int size) 創(chuàng)建epoll
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
第一個(gè)參數(shù)是epoll_create返回值钟沛,第二個(gè)參數(shù)代表操作,第三個(gè)參數(shù)代表監(jiān)聽(tīng)的fd局扶,第四個(gè)參數(shù)是告訴內(nèi)核需要監(jiān)聽(tīng)什么事
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)

等待事件的產(chǎn)生恨统,類(lèi)似于select()調(diào)用。參數(shù)events用來(lái)從內(nèi)核得到事件的集合三妈,maxevents表示每次能處理的最大事件數(shù)畜埋,告之內(nèi)核這個(gè)events有多大,這個(gè)maxevents的值不能大于創(chuàng)建epoll_create()時(shí)的size畴蒲,參數(shù)timeout是超時(shí)時(shí)間(毫秒悠鞍,0會(huì)立即返回,-1將不確定模燥,也有說(shuō)法說(shuō)是永久阻塞)咖祭。該函數(shù)返回需要處理的事件數(shù)目,如返回0表示已超時(shí)蔫骂。

handler里面都是怎樣的
epoll_create:
mEpollFd = epoll_create(EPOLL_SIZE_HINT);

epoll_ctl:
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeEventFd;
int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);

epoll_wait:
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

native looper機(jī)制是怎樣的么翰?

通過(guò)addfd來(lái)實(shí)現(xiàn)的。也是通過(guò)epoll來(lái)實(shí)現(xiàn)等待纠吴,可以有callback硬鞍。
https://blog.csdn.net/chwan_gogogo/article/details/46953563

已經(jīng)有消息在處理的情況下,需要喚醒嗎戴已?

不需要9谈谩!

   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(TAG, 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) {   //可以看到這里有判斷糖儡,needWake才喚醒的伐坏。
                nativeWake(mPtr);
            }
        }
        return true;
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市握联,隨后出現(xiàn)的幾起案子桦沉,更是在濱河造成了極大的恐慌每瞒,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纯露,死亡現(xiàn)場(chǎng)離奇詭異剿骨,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)埠褪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)浓利,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人钞速,你說(shuō)我怎么就攤上這事贷掖。” “怎么了渴语?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵苹威,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我驾凶,道長(zhǎng)牙甫,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任调违,我火速辦了婚禮腹暖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘翰萨。我一直安慰自己脏答,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布亩鬼。 她就那樣靜靜地躺著殖告,像睡著了一般。 火紅的嫁衣襯著肌膚如雪雳锋。 梳的紋絲不亂的頭發(fā)上黄绩,一...
    開(kāi)封第一講書(shū)人閱讀 51,727評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音玷过,去河邊找鬼爽丹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛辛蚊,可吹牛的內(nèi)容都是我干的粤蝎。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼袋马,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼初澎!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起虑凛,我...
    開(kāi)封第一講書(shū)人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤碑宴,失蹤者是張志新(化名)和其女友劉穎软啼,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體延柠,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡祸挪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了贞间。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片匕积。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖榜跌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情盅粪,我是刑警寧澤钓葫,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站票顾,受9級(jí)特大地震影響础浮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜奠骄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一豆同、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧含鳞,春花似錦影锈、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至熔吗,卻和暖如春辆床,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背桅狠。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工讼载, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人中跌。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓咨堤,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親漩符。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吱型,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

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