最近翻譯了一片關(guān)于Context泄露的文章,其中提到了Handler的一些知識點。想想當初自己研究這塊的時候也是看著源碼一點點摳出來的。只不過那時候沒有做個總結(jié)馍悟,現(xiàn)在正好借著這個機會把這塊知識點總結(jié)下糠悯,也算是做個備注了。
我們知道Android應(yīng)用啟動的時候會執(zhí)行ActivityThread類的main方法东臀,詳情請參見羅升陽的這篇文章。main方法中會為主線程創(chuàng)建一個Looper對象犀农,這個Looper中維護了一個消息隊列MessageQueen惰赋。Looper會不斷的從消息隊列中取消息,然后交給消息的target對象(即Handler)去處理這個消息呵哨。如果隊列中沒有消息赁濒,那么Looper就會進入等待狀態(tài)直到隊列中有新消息。大概的過程就是這樣孟害,下面我們通過源碼來了解下整個過程拒炎。
首先來看看ActivityThread的main方法,這里只保留了跟本文相關(guān)的主要代碼挨务。
public static void main(String[] args) {
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Looper.loop();
}
main方法中首先調(diào)用了Looper.prepareMainLooper()
來為主線程創(chuàng)建一個Looper對象击你,然后在調(diào)用Looper.loop()
方法進入一個無限循環(huán)狀態(tài)不斷的從消息隊列中取消息進行處理。那么谎柄,我們再跟蹤到Looper.prepareMainLooper()
中去看看丁侄。
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));
}
prepareMainLooper()
首先調(diào)用Looper的prepare()
方法創(chuàng)建Looper對象,然后再把這個looper對象賦值給sMainLooper朝巫。同時在創(chuàng)建過程中確保了主線程只有一個Looper對象鸿摇。Looper對象在創(chuàng)建的時候會同時創(chuàng)建一個MessageQueen對象,所有的消息都會存儲在這個隊列中劈猿。Looper也是從這個隊列中取消息來進行處理的拙吉。并且,這個Looper對象的作用域為整個線程揪荣。 這樣筷黔,只要是在該線程內(nèi)發(fā)送的消息,都會發(fā)送到這個Looper對象的消息隊列中進行處理仗颈。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
main方法最后調(diào)用了Looper的loop()
方法讓Looper工作起來佛舱,也就是處理消息隊列中的消息。
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg);
}
}
loop()
方法先拿到當前線程的Looper對象,然后再拿到Looper的MessageQueen對象名眉。最后進入無限循環(huán),不斷的從消息隊列中取出消息凰棉。然后再把消息交給這個消息的target對象進行處理损拢。那么現(xiàn)在的問題就是消息是從哪里來的以及這個target對象又是誰。
一般情況下撒犀,我們會通過handler的sendMessage(msg)
方法來發(fā)送一條消息福压。那么我們就跟蹤下這個方法,看看這個消息最終被發(fā)送到哪里去了或舞。
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;//注意:這里把this(即發(fā)送消息的那個Handler對象)賦值給了消息的target對象荆姆。
//所以,在Looper.loop()方法中的target就是一個Handler對象
return queue.enqueueMessage(msg, uptimeMillis);
}
可以看到通過層層調(diào)用映凳,最終調(diào)用了sendMessageAtTime()
方法胆筒,該方法又調(diào)用了enqueueMessage()
方法將方法放入一個消息隊列中。那么這個消息隊列又跟Looper中的消息隊列有啥關(guān)系呢诈豌?我們來看看Handler是怎么創(chuàng)建的仆救。
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
}
已經(jīng)很清晰明了了。當創(chuàng)建Handler對象的時候矫渔,首先會通過Looper.myLooper()
拿到當前線程的Looper對象彤蔽,然后再拿到Looper的MessageQueen對象。也就是說我們的消息是被發(fā)送到當前線程的Looper的消息隊列中了庙洼。這樣Looper.loop()
拿到的消息就是我們發(fā)送的消息顿痪,然后再把消息交給發(fā)送這個消息的Hanlder來進行處理。即Looper.loop()
中的msg.target.dispatchMessage(msg)
油够。那么我們再來看看handler.dispatchMessage(msg)
是怎么處理這個消息的蚁袭。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
我們這里暫時不關(guān)心msg的callback以及handler的mCallback。這里最終會調(diào)用handleMessage(msg)
方法叠聋,那我們當然要追蹤進去看看了撕阎。
public void handleMessage(Message msg) {
}
沒錯,是個空方法碌补。其實這里就是我們使用Handler的時候?qū)崿F(xiàn)我們處理消息邏輯的地方虏束。一般我們是這么使用Handler的:
private static Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//處理邏輯
}
};
至此,整個Handler機制就串通了:從消息的發(fā)送到消息的處理厦章。
如果我們在主線程中使用Handler镇匀,那我們不用去管Looper。因為袜啃,framew已經(jīng)為我們的主線程創(chuàng)建好了Looper汗侵。但是台夺,如果我們要在其他線程中使用Handler這套機制,那我們就需要自己去創(chuàng)建Looper并調(diào)用Looper.prepare()
宰睡,否則就會發(fā)生異常拆魏。