Android Framework提供的一個基礎組件,用於線程間通訊。主要是子線程UI更細消息傳遞給主線程,從而主線程更新UI。java
Android 主線程的UI,只能主線程更新。 若是多個線程都能更新,勢必要「加鎖」,還不如採用「單線程消息隊列機制」android
主線程內部維護一個循環。沒有消息時候,這個循環是阻塞的。新來消息(或者阻塞timeout)時會喚醒,接着處理新到來消息。git
整個handler能夠粗略的分爲三個過程數組
咱們使用Handler第一感官是發消息,因此從發消息切入。緩存
咱們先來看發送消息,這是咱們最簡單的一種發送消息的方式。markdown
//構建一個處理message的handler
val handler = object : Handler() {
override fun dispatchMessage(msg: Message) {
Log.d("alvin", "msg.what:${msg.what}")
}
}
var msg = Message().also { it.what = 1 }
handler.sendMessageDelayed(msg,1000L)
複製代碼
稍稍追蹤下代碼咱們發現,有不少sendMessage方式,都統一到一個方法中即app
//Handler.java
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;//這個分發用的,省略了一下其餘代碼
return queue.enqueueMessage(msg, uptimeMillis);
}
複製代碼
接着調用到MessageQueue.enqueueMessage(Message msg, long when),代碼在下面, 解釋下,咱們有一個單鏈表message,message有next指向下一個message,以及此message觸發時間when。單鏈表是有順序的,when越小,就越靠前。 根據when,新message插入合適位置,若是剛好插在隊首,則須要喚醒nativeWake。因此歸結下來兩件事情:入隊和喚醒。ide
//MessageQueue.java 忽略一些代碼了,只關心,咱們此次走到的邏輯
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
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 {
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) break;
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
if (needWake) nativeWake(mPtr);
}
return true;
}
複製代碼
咱們主要到構建一個Handler會調用到MessageQueue.javaoop
val handler = object : Handler()
-->mLooper = Looper.myLooper();
-->sThreadLocal.get()
ActivityTread.main()
-->Looper.prepareMainLooper()//構建當前線程的Looper
-->Looper.prepare()
-->new Looper(quitAllowed)
-->mQueue = new MessageQueue(quitAllowed);
-->mPtr = nativeInit()
-->Looper.loop();//啓動輪詢
複製代碼
那主線程的Looper哪裏來的,早在應用主線程被啓動時,咱們便post
//ActivityTread.java
class ActivityTread{
public static void main(String[] args) {
Looper.prepareMainLooper();
}
}
//Looper.java ,省略了部分代碼
class Looper{
/** *能夠看到sThreadLocal中的Looper只能被設置一次 */
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
/** * Initialize the current thread as a looper, marking it as an * application's main looper. The main looper for your application * is created by the Android environment, so you should never need * to call this function yourself. See also: {@link #prepare()} */
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
}
複製代碼
Looper.loop() 省略部分代碼。就堵塞在這了nativePollOnce(ptr, nextPollTimeoutMillis)。 此處沒有用java中的wait/notify堵塞,而是經過Linux的epoll機制
來堵塞,緣由是須要處理 native側
的事件。 沒有消息時堵塞並進入休眠釋放CPU資源,有消息時再喚醒線程。 epoll參考:epoll的本質
class Looper{
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
// 1.阻塞,直到next有返回值。
Message msg = queue.next();
//2.後面提到的消息分發處理
msg.target.dispatchMessage(msg);
}
}
}
class MessageQueue {
Message next() {
/**等於0時,不堵塞,當即返回; *大於0時,最長堵塞等待時間,期間有新消息進來,可能會了當即返回(當即執行); *等於-1時,無消息時,會一直堵塞; */
int nextPollTimeoutMillis = 0;
for (;;) {
//阻塞在此,超時或者被喚醒時,執行接下來的代碼
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null) {
if (now < msg.when) {
//咱們發現拿到的第一個消息,執行時間還沒到,那咱們計算下超時時間,用於下一次的nativePollOnce
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.提取這個消息,並如下一個消息從新做爲消息頭
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
}
}
}
}
複製代碼
在Looper.loop()中執行了 msg.target.dispatchMessage(msg); msg.target就是咱們的Handler對象。
早在Handler.enqueueMessage(msg,...)時,咱們執行了
msg.target = this;
class Handler{
public void dispatchMessage(@NonNull Message msg) {
//msg.callback跟蹤下代碼。哦,原來是post(Runnable),時候構建一個帶callback的message
if (msg.callback != null) {
handleCallback(msg);//-->message.callback.run();
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//咱們並無給handler設置mCallback,因此執行handleMessage
handleMessage(msg);
}
}
//post(Runnable),時候構建一個帶callback的message
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
}
複製代碼
雖然主流程沒有了問題,但咱們省略了不少代碼,能夠做爲問題來探索這些省略的代碼
消息輪詢機制是經過MessageQueue.nativePollOnce()掛起和MessageQueue.nativeWake喚醒。 MessageQueue經過mPtr變量保存NativeMessageQueue對象,從而使得MessageQueue成爲Java層和Native層的樞紐,既能處理上層消息,也能處理native層消息;下面列舉Java層與Native層的對應圖。 要注意的是Java層和C++層分別實現了一套Handler機制代碼。
Java層:new Looper()-->new MessageQueue()-->mPtr = MessageQueue.nativeInit() -->native層:android_os_MessageQueue_nativeInit()-->new NativeMessageQueue()-->new Looper(false) 最終走到了Looper.cpp的構造方法
Looper::Looper(bool allowNonCallbacks)
rebuildEpollLocked();
}
void Looper::rebuildEpollLocked() {
struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = EPOLLIN;//監聽mWakeEventFd有寫入數據。
eventItem.data.fd = mWakeEventFd.get();
//建立 eventpoll 對象,返回一個 epfd,即 eventpoll 句柄。
int result = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mWakeEventFd.get(), &eventItem);
}
複製代碼
要說 epoll_ctl()幹嗎用的,我也不太會了, 能夠參考。
從Java層分析咱們獲得Looper.loop()-->MessageQueue.nativePollOnce(mPtr,timeout) 進入native層:android_os_MessageQueue_nativePollOnce()-->NativeMessageQueue::pollOnce() -->Looper::pollOnce()-->Looper::pollInner() 一頓操做進入到了Looper::pollInner()
int Looper::pollInner(int timeoutMillis) {
//1.timeoutMillis處理,省略...
//2.開啓等待,監聽mWakeEventFd寫入事件
//events 表示回傳處理事件的數組;
//maxevents 表示每次能處理的最大事件數;
//timeout:等待 IO 的超時時間,-1 表示一直阻塞直到來 IO 被喚醒,大於 0 表示阻塞指定的時間後被喚醒
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
//3.後面等喚醒後執行,先執行native層添加的message,邏輯與java層處理消息相似。
//4.走回java層,MessageQueue.nativePollOnce(),執行java層的消息提取。
}
複製代碼
根據前面Java層分析,進入到MessageQueue.nativeWake() 進入native層:android_os_MessageQueue_nativeWake()-->NativeMessageQueue::wake()-->Looper::wake() 一頓操做進入Looper::wake()
void Looper::wake() {
uint64_t inc = 1;
//往mWakeEventFd裏面寫了1,隨後進入到Looper::pollInner(),喚起」epoll_wait「,繼續執行。
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
}
複製代碼
int Looper::pollInner(int timeoutMillis) {
//1.timeoutMillis處理,省略...
//2.開啓等待,監聽mWakeEventFd寫入事件,省略...
int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
//Looper::wake()後執行到這。
//3.後面等喚醒後執行,先執行native層添加的message,邏輯與java層處理消息相似
while (mMessageEnvelopes.size() != 0) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
if (messageEnvelope.uptime <= now) {
sp<MessageHandler> handler = messageEnvelope.handler;
Message message = messageEnvelope.message;
mMessageEnvelopes.removeAt(0);
handler->handleMessage(message);
} else {
// The last message left at the head of the queue determines the next wakeup time.
mNextMessageUptime = messageEnvelope.uptime;
break;
}
}
//4.走回java層,MessageQueue.nativePollOnce(),執行java層的消息提取。
}
複製代碼
與Java層相似,但同時咱們省略了不少代碼,帶着問題繼續看代碼