子線程的Handler
在使用handler時,會有在子線程建立handler的場景,那我們從Looper.java的源碼中摘抄下面一段建立Hander的代碼段:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
上面是一般使用在子線程建立和使用Handler的代碼段,我們對比以前在主線程建立和使用Handler的代碼,可以發現基本差不多,但是有一點不一樣,那就是在子線程中多了下面這兩行代碼:
Looper.prepare();
Looper.loop();
1.1 prepare
就是子線程需要prepare,可以直接了解為組要準備目前線程的looper。就是說子線程沒有looper,那我們看看我們怎麼準備looper的?
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static void prepare() {
prepare(true);
}
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));
}
源碼的注釋也說得很清楚,就是建立handler需要先有looper。prepare()方法裡面是調用了prepare(boolean quitAllowed)方法,後面這個方法比前面就多了個參數,這個參數【quitAllowed】看字面意思可以看出作用就是:允不允許looper退出,從代碼中我們可以知道子線程的looper是可以退出的;然後在prepare(boolean quitAllowed)中首先檢查時候已經存在looper了,如果已經含有了looper,那就報錯,這下我們就知道了Android是怎麼保證一個線程隻有一個looper了,如果目前線程還不存在looper,那就直接new一個新的looper,然後将建立的looper塞進sThreadLocal中。
1.2 loop
那麼子線程中loop()方法是什麼呢?這個loop()方法就是在目前線程中運作消息隊列,并切在結束時需要調用quit()方法.我們接着針對loop()看看源碼裡面做了什麼:
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the 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;
for (;;) {
Message msg = queue.next(); // might block
...
try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
}
....
msg.recycleUnchecked();
}
}
在loop()方法中主要就是從消息隊列中擷取消息,然後執行資訊分發【這個具體先不深入,我們隻要知道loop()的主要工作就行】,對比一下我們在主線程中使用Handler的情況,在子線程中使用Handler很像是條件不好人要自立更生艱苦奮鬥,沒有條件就自己創造條件。
主線程的Handler
我們看了子線程中如何使用Handle和相關源碼分析,接下來再看看主線程中我們是怎麼使用handler的?根據以前的經驗,主線程建立使用Handler就是直接建立的,并沒有其他的操作:
public Handler mHandler;
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
相比子線程,使用時少了prepare()和loop();但是真的是主線程不需要調用這些方法嗎?顯然不是的,子線程有的主線程也不能少,那接下來我們看看是誰幫了我們的忙?
還記得之前在Android_Application啟動梳理時,就發現了在ActivityThread的面main函數就有這麼兩行行代碼:
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
Looper.loop();
}
2.1 prepareMainLooper
那我們就看看這個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();
}
}
這個prepareMainLooper()裡面就是調用了prepare()方法,但是傳入的參數和在子線程中不同,這裡這傳入的是false,也就是說主線程的looper是不允許退出的;到這裡,我們知道prepareMainLooper将目前線程初始化為循環程式,将其标記為應用程式的主循環程式。應用程式的主循環是由android環境建立的,是以使用者不必自己調用此函數
2.2 loop
在prepareMainLooper()方法後也調用了loop()方法,看到這裡,我們就明白了主線程在使用handler的條件在建立程式之初就已經具備,是以讓使用者在主線程中使用handler也友善很多。
總結
1.也可以在子線程建立handler,需要提前prepare looper和自己調用loop。
2.主線程和子線程的差別:主線程的looper建立完後不可以退出,子線程建立的looper是可以退出的,需要自己去prepare()和loop(),主線程的handler環境在程序啟動的時候就建立好了。