Android 主線程之旅——PSVM(public static void main)
原文出處: Square官方技術博客 譯文出處: Android Cool Posts
當碰到與Android主線程交互相關的Bug時,我決定好好去看看Android的主線程究竟是怎么一回事。這篇文章就是描述我的Android主線程之旅的第一部分。
PSVM
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() 方法里面的代碼類似這樣:
public class BigBang { public static void main(String... args) { // The Java universe starts here. } }
每一個looper都會和一個線程綁定。要創建一個新的looper并將它同當前的線程綁定起來,你必須要調用Looper.prepare()方法。這些looper都被存儲在Looper 類里面的靜態ThreadLocal變量里面。你可以通過調用Looper.myLooper()方法來獲取與當前線程相關聯的Looper。
當然實際情況不要這么復雜,其實HandlerThread類已經幫你做了所有事情:
public class BigBang { public static void main(String... args) { // The Java universe starts here. } }
HandlerThread的內部代碼類似于這樣:
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發過來的消息。
class HandlerThread extends Thread { Looper looper; public void run() { Looper.prepare(); // 創建一個Looper對象并將它保存到一個ThreadLocal 對象里面。 looper = Looper.myLooper(); // 從ThreadLocal 里面獲取Looper以便后來的使用。 Looper.loop(); // Loop forever. } }
你可以為一個looper關聯多個handler。looper會把message發送到message.target(它就是一個handler)這里。
一個常用簡單的用法就是使用handler來發送一個Runnable對象:
//創建包含一個runnable引用的message,然后將這個message添加到這個looper的消息隊列 handler.post(new Runnable() { public void run() { // 這會在與handler相關聯的looper對應的線程上運行 } });
一個handler也可以在沒有設置looper的情況下被創建。:
//創建包含一個runnable引用的message,然后將這個message添加到這個looper的消息隊列 handler.post(new Runnable() { public void run() { // 這會在與handler相關聯的looper對應的線程上運行 } });
handler的無參構造函數會調用方法來獲取與當前線程相關聯的looper。這個時候你要注意,可能當前線程不是你的handler想關聯的線程。
大部分時間,你只需要創建一個在主線程上面發送消息的handler就行了:
//創建包含一個runnable引用的message,然后將這個message添加到這個looper的消息隊列 handler.post(new Runnable() { public void run() { // 這會在與handler相關聯的looper對應的線程上運行 } });
Back to PSVM
讓我們再來看看ActivityThread.main()這個方法。下面就是這個方法的一些內部實現:
//創建包含一個runnable引用的message,然后將這個message添加到這個looper的消息隊列 handler.post(new Runnable() { public void run() { // 這會在與handler相關聯的looper對應的線程上運行 } });
現在你知道為什么這個線程被稱為主線程了吧:) .
注意: 主線程最先做的幾件事情之一就是創建Application對象,然后調用Application.onCreate()方法。