什么抖甘?View.post()沒執(zhí)行热鞍?!

在工作中碰到了這樣一個問題衔彻,在RecyclerViewonBindViewHolder里執(zhí)行了下面的代碼:

@Override
        public void onBindViewHolder(CategoryFragment.ViewHolder holder, int position) {
            ......
            Task.callInBackground{
                ......
                mView.post(new Runnable() {
                    @Override
                    public void run() {
                        //do something
                    }
                });
            }
        }

簡單說就是在異步線程調(diào)用View.post()將某些邏輯分發(fā)至主線程執(zhí)行薇宠,然而這個runnable的代碼并沒有被執(zhí)行。

View.post的官方注釋是這樣寫的:Causes the Runnable to be added to the message queue. The runnable will be run on the user interface thread.將runnable添加到消息隊列艰额,runnable將會在UI線程執(zhí)行澄港,好像沒什么問題,那為什么這里沒有執(zhí)行呢柄沮?我們來看一下它的源碼:

public boolean post(Runnable action) {
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) {
        return attachInfo.mHandler.post(action);
    }
    // Assume that post will succeed later
    ViewRootImpl.getRunQueue().post(action);
    return true;
}

這下好像發(fā)現(xiàn)問題了回梧,他是通過attachInfo中的Handler來執(zhí)行runnable的废岂,如果這個attachInfo為空,則將runnable加入到ViewRootImplRunQueue中等待狱意,那么這個attachInfo什么時候被賦值呢湖苞?答案是View attach到window上的時候。

void dispatchAttachedToWindow(AttachInfo info, int visibility) {
        mAttachInfo = info;
        ......
}

也就是說onBindViewHolder的時候View還沒有attach到window详囤,看一下log,確實如此财骨。知道了為什么不執(zhí)行,那么解決起來就很簡單了藏姐,直接new一個Handler來執(zhí)行這些任務(wù)就好了隆箩。

Console Output

不過這個runnable不是被加到了一個RunQueue里么,Google還寫了注釋說假設(shè)這個runnable一會兒會成功執(zhí)行包各,一會兒是多大一會兒呢摘仅?繼續(xù)看源碼,RunQueue的源碼是這樣寫的:

    /**
     * The run queue is used to enqueue pending work from Views when no Handler is
     * attached.  The work is executed during the next call to performTraversals on
     * the thread.
     * @hide
     */

RunQueue是在View還沒有attach到window上问畅,即沒有handler的時候用來執(zhí)行后續(xù)任務(wù)的娃属,這些任務(wù)會在下一次調(diào)用performTraversals的時候執(zhí)行,好吧护姆,你贏了矾端。。卵皂。

    static final class RunQueue {
        //儲存所有的runnable
        private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();
        //View沒有attach到window秩铆,View.post()最終調(diào)用到這里
        void post(Runnable action) {
            postDelayed(action, 0);
        }
        void postDelayed(Runnable action, long delayMillis) {
            HandlerAction handlerAction = new HandlerAction();
            handlerAction.action = action;
            handlerAction.delay = delayMillis;

            synchronized (mActions) {
                mActions.add(handlerAction);
            }
        }
        //View沒有attach到window,View.removeCallbacks最終調(diào)用到這里
        void removeCallbacks(Runnable action) {
            final HandlerAction handlerAction = new HandlerAction();
            handlerAction.action = action;

            synchronized (mActions) {
                final ArrayList<HandlerAction> actions = mActions;

                while (actions.remove(handlerAction)) {
                    // Keep going
                }
            }
        }
        //執(zhí)行所有runnable灯变,在ViewRootImpl.performTraversals()中被調(diào)用
        void executeActions(Handler handler) {
            synchronized (mActions) {
                final ArrayList<HandlerAction> actions = mActions;
                final int count = actions.size();

                for (int i = 0; i < count; i++) {
                    final HandlerAction handlerAction = actions.get(i);
                    handler.postDelayed(handlerAction.action, handlerAction.delay);
                }

                actions.clear();
            }
        }

        //對runnable的簡單封裝
        private static class HandlerAction {
            Runnable action;
            long delay;
            ......
        }
    }

谷爹可能也意識到這非常的不科學(xué)殴玛,讓人難以理解,所以添祸。滚粟。。爸爸在7.0以上給你修好了刃泌,啊哈哈凡壤!好吧,我們來看Google爸爸改了什么耙替,其實非常的簡單亚侠!首先簡單優(yōu)化了一下RunQueue,改了個名字叫HandlerActionQueue了俗扇,View.post()的流程也基本沒有什么變化硝烂,然后最關(guān)鍵的一點來了:

void dispatchAttachedToWindow(AttachInfo info, int visibility) {
        mAttachInfo = info;
        ......
        // Transfer all pending runnables.
        if (mRunQueue != null) {
            mRunQueue.executeActions(info.mHandler);
            mRunQueue = null;
        }
        ......
    }

在view attachedToWindow的時候執(zhí)行RunQueue中所有沒執(zhí)行的任務(wù),就是這么easy铜幽。

總結(jié):

View.post()只有在View attachedToWindow的時候才會立即執(zhí)行钢坦。

在attach之前調(diào)用的話究孕,低于7.0時可以自己new一個Handler或者自定義View重寫dispatchAttachedToWindow自己儲存pendingTask并在attached之后執(zhí)行。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末爹凹,一起剝皮案震驚了整個濱河市厨诸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌禾酱,老刑警劉巖微酬,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異颤陶,居然都是意外死亡颗管,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門滓走,熙熙樓的掌柜王于貴愁眉苦臉地迎上來垦江,“玉大人,你說我怎么就攤上這事搅方”瓤裕” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵姨涡,是天一觀的道長衩藤。 經(jīng)常有香客問我,道長涛漂,這世上最難降的妖魔是什么赏表? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮匈仗,結(jié)果婚禮上瓢剿,老公的妹妹穿的比我還像新娘。我一直安慰自己悠轩,他們只是感情好跋选,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著哗蜈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪坠韩。 梳的紋絲不亂的頭發(fā)上距潘,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機與錄音只搁,去河邊找鬼音比。 笑死,一個胖子當(dāng)著我的面吹牛氢惋,可吹牛的內(nèi)容都是我干的洞翩。 我是一名探鬼主播稽犁,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼骚亿!你這毒婦竟也來了已亥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤来屠,失蹤者是張志新(化名)和其女友劉穎虑椎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俱笛,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡捆姜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了迎膜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泥技。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖磕仅,靈堂內(nèi)的尸體忽然破棺而出珊豹,到底是詐尸還是另有隱情,我是刑警寧澤宽涌,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布平夜,位于F島的核電站,受9級特大地震影響卸亮,放射性物質(zhì)發(fā)生泄漏忽妒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一兼贸、第九天 我趴在偏房一處隱蔽的房頂上張望段直。 院中可真熱鬧,春花似錦溶诞、人聲如沸鸯檬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喧务。三九已至,卻和暖如春枉圃,著一層夾襖步出監(jiān)牢的瞬間功茴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工孽亲, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留坎穿,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像玲昧,于是被迫代替她去往敵國和親栖茉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

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