當碰到與Android主執行緒互動相關的Bug時,我決定好好去看看Android的主執行緒究竟是怎麼一回事。這篇文章就是描述我的Android主執行緒之旅的第一部分。
PSVM
1 2 3 4 5 |
public class BigBang { public static void main(String... args) { // The Java universe starts here. } } |
眾所周知,所有的Java程式的入口都是 public static void main()
方法。這對所有的Java 桌面程式、J2EE以及Android程式都是成立的。
當Android啟動時,它會開啟一個叫做 ZygoteInit
的Linux程式。這個程式是一個Dalvik 虛擬機器,它會在一個執行緒上面載入Android SDK裡面大部分的常用類,然後等待。
當Android啟動一個新的Android程式時,Android系統會 fork
這個ZygoteInit
程式。接著子程式裡面的執行緒會停止等待,然後呼叫ActivityThread.main()
方法。
Wikipedia上面的一個Zygote。根據Wikipedia的定義,一個 Zygote 就是一個受精卵細胞。
Loopers
在繼續深入之前,我們需要來看一看Looper
這個類。
使用looper可以連續地為一個執行緒處理它的訊息。
每一個looper都有一個訊息佇列(一個 MessageQueue
)。
每一個looper都有一個處理訊息佇列裡面所有訊息的loop()方法,這個方法會在訊息佇列為空時阻塞。
Looper.loop() 方法裡面的程式碼類似這樣:
1 2 3 4 5 6 7 |
void loop() { while(true) { Message message = queue.next(); // blocks if empty. dispatchMessage(message); message.recycle(); } } |
每一個looper都會和一個執行緒繫結。要建立一個新的looper並將它同當前的執行緒繫結起來,你必須要呼叫Looper.prepare()
方法。這些looper都被儲存在Looper 類裡面的靜態ThreadLocal
變數裡面。你可以通過呼叫Looper.myLooper()
方法來獲取與當前執行緒相關聯的Looper。
當然實際情況不要這麼複雜,其實HandlerThread
類已經幫你做了所有事情:
1 2 3 |
HandlerThread thread = new HandlerThread("SquareHandlerThread"); thread.start(); // starts the thread. Looper looper = thread.getLooper(); |
HandlerThread
的內部程式碼類似於這樣:
1 2 3 4 5 6 7 8 |
class HandlerThread extends Thread { Looper looper; public void run() { Looper.prepare(); // 建立一個Looper物件並將它儲存到一個ThreadLocal 物件裡面。 looper = Looper.myLooper(); // 從ThreadLocal 裡面獲取Looper以便後來的使用。 Looper.loop(); // Loop forever. } } |
Handlers
handler 天生就是 looper 的好夥伴。
一個 handler 有兩個作用:
- 從任意執行緒傳送訊息給一個looper的訊息佇列;
- 處理相關聯的looper發過來的訊息。
12345678910111213141516// Each handler is associated to one looper.Handler handler = new Handler(looper) {public void handleMessage(Message message) {// Handle the message on the thread associated to the given looper.if (message.what == DO_SOMETHING) {// do something}}};// Create a new message associated to that handler.Message message = handler.obtainMessage(DO_SOMETHING);// Add the message to the looper queue.// Can be called from any thread.handler.sendMessage(message);
你可以為一個looper關聯多個handler。looper會把message傳送到message.target(它就是一個handler)這裡。
一個常用簡單的用法就是使用handler來傳送一個Runnable
物件:
1 2 3 4 5 6 |
//建立包含一個runnable引用的message,然後將這個message新增到這個looper的訊息佇列 handler.post(new Runnable() { public void run() { // 這會在與handler相關聯的looper對應的執行緒上執行 } }); |
一個handler也可以在沒有設定looper的情況下被建立。:
1 2 |
// DON'T DO THIS Handler handler = new Handler(); |
handler的無參建構函式會呼叫方法來獲取與當前執行緒相關聯的looper。這個時候你要注意,可能當前執行緒不是你的handler想關聯的執行緒。
大部分時間,你只需要建立一個在主執行緒上面傳送訊息的handler就行了:
1 |
Handler handler = new Handler(Looper.getMainLooper()); |
Back to PSVM
讓我們再來看看 ActivityThread.main()
這個方法。下面就是這個方法的一些內部實現:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class ActivityThread { public static void main(String... args) { Looper.prepare(); // You can now retrieve the main looper at any time by calling Looper.getMainLooper(). Looper.setMainLooper(Looper.myLooper()); // Post the first messages to the looper. // { ... } Looper.loop(); } } |
現在你知道為什麼這個執行緒被稱為主執行緒了吧:) .
注意: 主執行緒最先做的幾件事情之一就是建立Application
物件,然後呼叫Application.onCreate()
方法。