今天重點研究下 handler 訊息延遲
handler 的 sendmessagedelayed
public final boolean sendmessagedelayed(message msg, long delaymillis)
return sendmessageattime(msg, systemclock.uptimemillis() + delaymillis);
}public boolean sendmessageattime(message msg, long uptimemillis)
此時的 uptimemillis 是當前時間 + 延遲時間,必定會大於 0 的。
private boolean enqueuemessage(messagequeue queue, message msg, long uptimemillis)
return queue.enqueuemessage(msg, uptimemillis);
}
我們知道在 messagequeue 中加入訊息
boolean enqueuemessage(message msg, long when) else
if (needwake)
}return true;
}
如果 p == null,則證明當前訊息佇列沒有訊息。
如果 when == 0,則是呼叫 handler 的 sendmessageatfrontofqueue 傳送訊息。
public final boolean sendmessageatfrontofqueue(message msg)
如果 when < p.when,則是新來的訊息比第乙個訊息還早。
這三種情況將 mmessages 設定為新訊息,新訊息的下乙個訊息next則為原來的訊息。也就是說將訊息插入到佇列的頭節點。
boolean enqueuemessage(message msg, long when) else
if (needwake && p.isasynchronous())
}msg.next = p; // invariant: p == prev.next
prev.next = msg;
}if (needwake)
}return true;
}
如果三種情況都不符合,遍歷當前訊息佇列,將新訊息的 when 與訊息佇列中訊息的 when 比較,新訊息再插入到佇列中。此時佇列也就是按照 when 的佇列。
此時 needwake 為 true(後續再理解 needwake ),呼叫 nativewake,由前兩節知道,這裡在 eventfd 中寫入資料了。
接下來再看下訊息迴圈
message next()
if (msg != null) else else
msg.next = null;
msg.markinuse();
return msg;
}} else
//idlehandler相關
}//idlehandler相關
nextpolltimeoutmillis = 0;
}}
這段**,首先 nextpolltimeoutmillis 為 0 時 nativepollonce 喚醒,或者之前傳送訊息使 nativepollonce 喚醒。取出訊息佇列頭節點的訊息,這個訊息的 when 自然使最小。與當前時間 now 比較。
如果比當前時間大的話,說明頭節點的訊息還沒有觸發,計算插值 nextpolltimeoutmillis。相反,則取出此次訊息進行分發處理。
而計算出的 nextpolltimeoutmillis,則迴圈給 nativepollonce 的引數,重新設定等待時間。
訊息延遲總結
1、訊息佇列按照訊息觸發的事件進行排序。
2、設定 epoll_wait 的超時時間,使其在待定的時間喚醒。
3、訊息延遲的精度不高,如果訊息佇列中處理訊息比較耗時,會導致後面訊息延遲處理。
Handler原始碼解析
意思就是說 在沒有呼叫looper.prepare 之前不能在子執行緒建立handler。為什麼在主線程中我們就已經可以直接建立handler?因為在activity的啟動 中,已經在當前ui執行緒 主線程 呼叫了looper.preparemainlooper 和looper.loop 方法。我們...
handler原始碼分析
昨天研究了一下handler的原始碼,今天總結一下 android只有乙個執行緒可以操作ui介面,我們稱之為ui執行緒。每個ui執行緒都維護乙個looper,這個looper中有乙個messagequeue來儲存ui乙個訊息佇列。通過控制這個訊息佇列來實現對ui介面的順序重新整理。handler.s...
Handler原始碼分析
當程式執行時,會先執行activitythread的main方法。會執行looper.preparemainlooper 方法和looper.loop 方法。looper.preparemainlooper public static void preparemainlooper smainloop...