Handler 常用的方法
- Handler.postDelayed(Runnable r, long delayMillis)
- Handler.sendMessageDelayed(getPostMessage(r), delayMillis)
- Handler.sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)
- Handler.enqueueMessage(queue, msg, uptimeMillis)
- MessageQueue.enqueueMessage(msg, uptimeMillis)
那么 handler.postDelayed 和 handler sendMessageDelayed是如何實現時間精准發送消息
handler 在發送消息后,消息會放入MessageQueue中,MessageQueue是一個簡單的單向鏈表
在插入的時候會判斷當前消息距離要執行時間和鏈表中所有消息距離要執行時間大小的比較
鏈表頭時間短,鏈表尾時間長。
然后再Looper 循環取MessageQueue中的消息的時候會判斷當前時間是否是消息可以處理的時間
如果不是,則調用nativePollOnce 進行阻塞,阻塞時間到了,再去取消息
for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } nativePollOnce(ptr, nextPollTimeoutMillis); 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) { // 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) { // 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; } ... } }
handler snet 和 post 本質沒有區別都是向messageQueue中加入了消息
有區別在於回調方式的不同,post runnable 回調是回到run方法中
sent 最終會調用到handlerMessage 我們復寫的這個方法這里
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } //獲得了message實例,將r賦給callback,接下來還是和sendMessage一致的操作,進入sendMessageDelayed private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; } public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
最終還是到sendMessageAtTime這個方法里面
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); }
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { //如果是post,callback不為空,直接進入handleCallback if (msg.callback != null) { handleCallback(msg); } else { //如果是sendMessage,且創建handler時沒有傳入callback,則callback為空,直接進入handleMessage,也就是我們自己復寫的處理Message的方法 if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } //直接run並不會啟動新線程,所以這就是post的runnable里面可以直接更新UI的原因 private static void handleCallback(Message message) { message.callback.run(); }
