Android的消息機制幾乎是面試必問的話題,當(dāng)然也并不是因為面試脸侥,而去學(xué)習(xí)畏纲,更重要的是它在Android的開發(fā)中是必不可少的扇住,占著舉足輕重的地位,所以弄懂它是很有必要的霍骄。下面就來說說最基本的東西台囱。
Looper
作用:
- 關(guān)聯(lián)起Thread
- 循環(huán)取出消息
1、Looper是否可以直接實例化读整?
Looper構(gòu)造方法是私有的,其中做了兩件事
- 創(chuàng)建一個MessageQueue
- 得到與之對應(yīng)的Thread
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
2咱娶、一個線程能對應(yīng)多個Lopper米间?
不能,一個線程對應(yīng)一個Looper對象膘侮,通過ThreadLocal保證一個線程只有一個Looper與之對應(yīng)屈糊,如果多次調(diào)用Looper.prepare()
;則會拋出運行時異常。
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) { // 查看是否有l(wèi)ooper與當(dāng)前線程對應(yīng)
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
3琼了、Looper是無限循環(huán)逻锐,會阻塞嗎?
是雕薪,當(dāng)開啟一個loop后是一個死循環(huán)昧诱,從MessageQueue中取出消息,處理消息所袁,但是也有可能退出盏档,在沒有消息后退出循環(huán)。
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;
// 略
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) { // 當(dāng)沒有消息的時候燥爷,退出
// No message indicates that the message queue is quitting.
return;
}
// 略
msg.target.dispatchMessage(msg);
}
4蜈亩、可以再次調(diào)用Looper.prepareMainLooper嗎?
不可以前翎,Looper.prepareMainLooper最終也是調(diào)用prepare()稚配,同2.
public static void prepareMainLooper() {
prepare(false); // 創(chuàng)建一個Looper
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
5、MainLooper什么時候創(chuàng)建的港华?
MainLooper是啟動Activity創(chuàng)建ActivityThread(并不是一個Thread)時候創(chuàng)建道川,所以不能多次創(chuàng)建。
public static void main(String[] args) {
// 略
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
// 略
ActivityThread thread = new ActivityThread();
thread.attach(false);
// 略
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// 略
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
}
Handler
作用:
- 發(fā)送消息到MessageQueue
- 處理消息
1、Handler如何與Looper愤惰、MessageQueue關(guān)聯(lián)起來苇经?
我們知道一個Looper對應(yīng)一個Thread,一個Looper包含一個MessageQueue宦言。當(dāng)我們創(chuàng)建Handler時就會從當(dāng)前線程中取出與之對應(yīng)的Looper扇单,讓后在從Looper中取出MessageQueue。
// 1奠旺、自動獲取
public Handler(Callback callback, boolean async) {
// 略
mLooper = Looper.myLooper(); // 取出當(dāng)前線程中的Looper
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue; // 取出MessageQueue
mCallback = callback;
mAsynchronous = async;
}
// 2蜘澜、傳遞一個Looper進來
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
Message
單項鏈表結(jié)構(gòu)。
作用:
- 數(shù)據(jù)的載體
1响疚、消息如何復(fù)用的鄙信?
從全局消息池(鏈表結(jié)構(gòu))中
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
2、Message為什么能傳遞忿晕?
Android中想要傳遞對象要么實現(xiàn)Serializable要么Parcelable装诡,在這里是實現(xiàn)了Parcelable接口。
public final class Message implements Parcelable {
// 略
}
3践盼、如何與Handler關(guān)聯(lián)鸦采?
我們知道在消息傳機制中Handler充當(dāng)著“快遞員”的角色,那么他又是如何與“貨物”--Message發(fā)生關(guān)系呢咕幻?實際上Message有一個成員變量target他的類型正是Handler渔伯,
/*package*/ Runnable callback;
public int arg1;
public int arg2;
public Object obj;
/*package*/ Handler target; // 關(guān)鍵點
當(dāng)我們通過Handler去send一個Message時候最終都會為target賦值為this,即當(dāng)前的Handler肄程。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; // 賦值語句
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
另為如果是通過Message.Obtain(),獲取的復(fù)用Message也會為其賦值锣吼。
多說一句,Handler.obtainMessage()調(diào)用的就是Message.Obtain()蓝厌。
public final Message obtainMessage(){
return Message.obtain(this);
}
總結(jié):
通過一系列的包涵關(guān)系玄叠,最終Looper、Handler褂始、Message诸典、MessageQueue即發(fā)生關(guān)聯(lián),從而形成一個閉合崎苗,開啟消息循環(huán)狐粱。
困惑
最近一直在看這方面的知識,但是能力有限胆数,還是有不少困惑肌蜻,如果有錯誤,或你理解下面的問題請聯(lián)系我fvaryu@qq.com,愿與君交流學(xué)習(xí)必尼,謝謝
1蒋搜、Message中的sPool篡撵,哪里初始化的?為什么Message.obtain()中不會拋異常豆挽?
2育谬、ActivityThread并不是線程,為什么可以創(chuàng)建一個Looper帮哈,Main Thread什么時候創(chuàng)建膛檀?
3、為什么序列化了的對象就可以傳遞娘侍?與Binder有關(guān)咖刃?
4、MessageQueue對應(yīng)的是NativeMessageQueue憾筏,具體實現(xiàn)需要學(xué)習(xí)嚎杨?
5、Loop.loop()氧腰,會退出嗎枫浙?退出時機是什么?如果會退出容贝,那么主線程同樣會退出嗎自脯?
原文鏈接