執行緒中更新 ui 的時候經常是呼叫 sendmessage() 和 sendmessagedelayed() 這樣 ,我跟蹤**進入到 handler 的 sendmessage() 方法:
public final boolean sendmessage(message msg)
public final boolean sendmessagedelayed(message msg, long delaymillis)
// systemclock.uptimemillis() + delaymillis 當前時間加上延遲時間
return sendmessageattime(msg, systemclock.uptimemillis() + delaymillis);
}public boolean sendmessageattime(message msg, long uptimemillis)
return enqueuemessage(queue, msg, uptimemillis);
}private boolean enqueuemessage(messagequeue queue, message msg, long uptimemillis)
return queue.enqueuemessage(msg, uptimemillis);
}
最後我們發現呼叫的是 messagequeue 的 enqueuemessage() 方法:
boolean enqueuemessage(message msg, long when)
// 有沒有在使用
if (msg.isinuse())
// 對當前訊息佇列加鎖。
synchronized (this)
// 標記訊息正在使用中
msg.markinuse();
msg.when = when;
message p = mmessages;
boolean needwake;
// 第一次新增資料到佇列中,或者當前 msg 的時間小於 mmessages 的時間
if (p == null || when == 0 || when < p.when) else
if (needwake && p.isasynchronous())
}// 把當前 msg 插入到列表中
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}// we can assume mptr != 0 because mquitting is false.
if (needwake)
}return true;
}
上面的這些**,我們始終沒有看到 handler 呼叫 handlemessage() 方法,但是有了乙個重要的結論,我們每傳送乙個訊息都被儲存到了 messagequeue 訊息佇列中,訊息佇列中採用的是單鏈表的方式。也就是說我如果用下面這段**傳送訊息,在 messagequeue 中應該是如圖所示。
// 傳送 message1
message message1 = new message();
mhandler.sendmessagedelayed(message1, 500);
// 傳送 message2
message message2 = new message();
mhandler.sendmessage(message2);
// 傳送 message3
2. loop 訊息迴圈
我們始終沒有看到 handler 呼叫 handlemessage() 方法,到底什麼時候會執行這個方法。待會解釋,先看一種現象,有時候我們像下面這麼寫會報錯:
必須要下面這樣寫才正常:
new thread()
}.start();
我們在 activity 中從來都沒有呼叫過 looper.prepare(); 這行**,為什麼就從來不報錯呢?我想你可能要去了解一下應用的啟動流程,或者看下我之前寫的 android外掛程式化架構 - activity的啟動流程分析 ,這裡我直接把 main 方法的**貼出來:
public static void main(string args)
looper.loop();
throw new runtimeexception("main thread loop unexpectedly exited");
}
其實不是不報錯,而是在 activitythread 的 main() 方法中系統早就幫我們寫好了,接下來我們豈不是只需要知道 looper.preparemainlooper() 和 looper.loop() 這兩行原始碼豈不就好了。先來看下 looper.preparemainlooper():
public static void preparemainlooper()
smainlooper = mylooper();
}}private static void prepare(boolean quitallowed)
sthreadlocal.set(new looper(quitallowed));
}public static @nullable looper mylooper()
這些**相對就比較簡單了,主要還是 threadlocal 的 set 方法,用來保證乙個執行緒只有乙個 looper 物件,這樣就保證了執行緒的安全。接下來看一下 looper.loop() 這行:
整體目錄.png
子執行緒更新ui.png
linux socket通訊原始碼
初學socket通訊,參考的是linuxc程式設計大全的23章的23 5例子,但是發現這個例子原始碼裡有好幾處錯誤,因為初學,很多不懂,吃了虧,因此將修改後能正常執行的 記錄在這裡 參考 server.c include include include include include include...
ucos II 任務間通訊原始碼分析
ucos ii 2.0版本的任務間通訊提供訊息郵箱和訊息佇列兩種機制,都基於核心的事件控制塊機制實現。訊息郵箱 訊息郵箱主要函式分析 訊息佇列 訊息佇列全域性變數 typedef struct os q os q typedef struct os q data os ext os q osqfre...
handler原始碼分析
昨天研究了一下handler的原始碼,今天總結一下 android只有乙個執行緒可以操作ui介面,我們稱之為ui執行緒。每個ui執行緒都維護乙個looper,這個looper中有乙個messagequeue來儲存ui乙個訊息佇列。通過控制這個訊息佇列來實現對ui介面的順序重新整理。handler.s...