android消息系統
整體架構如圖所示

在安卓的消息系統中,每個線程有一個Looper,Looper中有一個MessageQueue,Handler向這個隊列中投遞Message,Looper循環拿出Message再交由Handler處理。整體是一個生産者消費者模式,這四部分也就構成了android的消息系統。
先來看一個最簡單的例子
//這段代碼在某個Activity的onCreate中
Handler handler = new Handler(Looper.getMainLooper());
Message msg = Message.obtain(handler, new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext,"I am a message",Toast.LENGTH_SHORT).show();
}
});
handler.sendMessage(msg);
效果就是,在目前視窗彈出I am a message,當然就其實作的效果而言完全多此一舉。但是就分析android消息系統,卻是很簡單有效的例子。
源碼分析
Message
Message中封裝了我們常用的what、arg1、arg2、obj等參數,除此之外還有target:一個Handler類型,由前文可知一個Message最終還是交給一個Handler執行的,這個target存放的就是消息的目的地、callback,一個消息的回調,我們通過handler.post(new Runnable{…})發送的消息,這個Runnable即被存為callback。
首先來看消息的擷取:
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}
public static Message obtain(Handler h, Runnable callback) {
Message m = obtain();
m.target = h;
m.callback = callback;
return m;
}
對照最開始的例子,Message.obtain(Handler h, Runnable callback)首先調用obtain擷取了一個新的Message對象,然後為其設定了目的地Handler和回調函數callback,Message類中有很多不同的obtain函數,實際上隻是為我們封裝了一些指派的操作。
再看Message.obtain()方法,sPoolSync是一個給靜态方法用的靜态鎖,sPool是一個靜态的Message變量,在消息的擷取這裡,android使用了享元模式,對于會被重複使用的Message消息,沒有對每一次請求都建立一個對象,而是通過維護一個Message連結清單,在有空閑消息的時候從連結清單中拿Message,沒有時才建立Message。
可以看到obtain中隻有從連結清單中去Message和建立Message,而沒有向連結清單中存儲的過程。存儲這部分就要看Message.recycle()了:
public void recycle() {
clearForRecycle();
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
回收過程,首先把原連結清單的頭指向目前被回收消息的下一個節點,然後再把連結清單頭指針知道目前節點即可。整個操作也就是将Message添加到連結清單的首位。
MessageQueue 消息隊列
MessageQueue是在Looper中的,這點從Looper的構造函數可以看出來:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
對于每個MessageQueue,是連結清單實作的消息隊列。首先是入隊操作:
boolean enqueueMessage(Message msg, long when) {
if (msg.isInUse()) {
throw new AndroidRuntimeException(msg + " This message is already in use.");
}
if (msg.target == null) {
throw new AndroidRuntimeException("Message must have a target.");
}
synchronized (this) {
if (mQuitting) {
RuntimeException e = new RuntimeException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
return false;
}
msg.when = when;
//mMessages是連結清單的頭指針
Message p = mMessages;
boolean needWake;
if (p == null || when == || when < p.when) {
// 将消息插入到隊列的首位
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
//當抵達隊列尾部、或者目前消息的時間小于隊列中某消息的時間跳出循環
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
//将消息插入到連結清單中間(包含尾部)
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
next操作,包含取出和删除一條消息。
Message next() {
int pendingIdleHandlerCount = -; // -1 only during first iteration
int nextPollTimeoutMillis = ;
for (;;) {
if (nextPollTimeoutMillis != ) {
Binder.flushPendingCommands();
}
//從native層消息隊列取出消息
nativePollOnce(mPtr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// 找到非異步的Message或者消息隊列尾部的Message取出
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// 消息尚未到執行時間,下次循環挂起線程一段時間
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 擷取一個Message
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -;
}
// 檢查退出标志位
if (mQuitting) {
dispose();
return null;
}
...
}
}
Handler
Handler的作用是放入消息和處理消息,承擔了生産者的工作和部分消費者的工作。
首先通過Handler發送一條消息:
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, );
}
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
通過一層一層嵌套,真正的邏輯在sendMessageAtTime,可以看到僅僅是執行了一下入隊操作。作為生産者的工作也就執行完成,消費者部分後面要結合Looper分析。
除了sendMessage方法,常用的handler.post方法也是封裝為Message,主要過程和上面相似。
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), );
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
Looper
Looper類中,Looper的執行個體擷取是通過ThreadLocal的,ThreadLocal會為每一個線程提供一個副本,通過set和get方法每個線程擷取作用域僅屬于該線程的變量值。對于UI線程而言,會執行Looper.prepareMainLooper()來完成Looper的初始化:
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
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));
}
Looper.prepare()方法将目前線程的ThreadLocal設定了一個新的Looper對象,prepareMainLooper則是把目前線程的Looper對象指派給類變量sMainLooper ,該方法在ActivityThread中調用,設定了一個全局的給UI線程使用的Looper。
Looper的loop方法就是消費者的處理邏輯了:
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
//從Looper中擷取MessageQueue,循環取出消息
for (;;) {
Message msg = queue.next();
...
//将消息發送給目标處理。
msg.target.dispatchMessage(msg);
...
//回收消息,把消息放在消息池中
msg.recycle();
}
}
主要邏輯很清晰,前面分析過msg.target是一個Handler,表示處理消息的目标,通過指令模式将消息交給對應Handler處理。下面是Handler中處理消息的方法:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
public void handleMessage(Message msg) {
}
如果我們是通過handler.post的方法發送一條消息,那麼直接執行callback中的邏輯。否則通過實作Callback接口回調,或者執行handleMessage,handleMessage也就是我們子類覆寫的方法。可以看到,雖然邏輯部分是我們在Handler中實作的,但是調用的地方卻是Looper的線程。因為一個Looper綁定一個線程,我們也可以通過比較Looper來比較線程。
總結
通過分析源碼,可以知道android中可以通過Looper為每一個線程建立一個消息隊裡,UI線程的Looper在Activity啟動前就已經初始化。那麼對于我們自定義的線程,很明顯也可以綁定Looper。
自定義線程綁定Looper,最明顯的好處就是可以實作線程間通信了,同時由于借助了消息隊列,也将并行轉為串行實作了線程安全。看一個簡單的例子:
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
handlerA = new Handler(Looper.myLooper()){
@Override
public void handleMessage(Message msg) {
Log.d("TAG", msg.obj.toString());
}
};
Looper.loop();
}
}).start();
上述線上程中建立綁定了一個Looper,然後建立一個和目前Looper綁定的Handler,這樣可以通過該Handler向Looper的MessageQueue中添加消息,然後由Looper.loop取出消息并執行。
Message msg = new Message();
msg.obj = "i am main thread";
handlerA.sendMessage(msg);
在主線程或者其它線程中擷取handler然後發送消息,最終可以看到消息被線程接收并處理。這裡msg的target也就是handlerA。注意如果線程工作結束,需要調用Looper.quit(),不然會因為Looper一直循環而導緻線程無法結束。
最後經過上面的分析,流程圖可以畫的更為細緻: