Handler原始碼解讀(三)

2021-10-04 06:31:30 字數 2085 閱讀 9572

今天重點研究下 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...