1.首先看一段App應用程序啟動的時候的源碼流程分析圖(網(wǎng)上看到的):
從上圖我們可以看到:當我們點擊桌面的應用程序的圖標的時候芳来,首先會通過Binder的IPC通信機制,啟動ActivityManagerService的startActivity方法猜拾,如果發(fā)現(xiàn)進程沒有啟動的話即舌,需要通過zygote(受精卵)孵化出一個新的進程,在新的進程中執(zhí)行ActivityThread的main方法挎袜。
2.我們在獲取到Looper.getMainLooper()是通過sMainLooper來獲取的顽聂,那這個sMainLooper是在哪里賦值的?
答:首先我們看到在Looper中有一個方法prepareMainLooper(),該方法會對sMainLooper進行初始化盯仪,那么我們在什么時候會調(diào)用該方法呢紊搪,為什么我們在主線程中創(chuàng)建handler的時候,不需要手動去調(diào)用這個方法全景,而是直接利用handler的構造方法耀石,不需要對looper進行處理就創(chuàng)建呢?
細看framework的源碼爸黄,可以看到整個 Framework 框架只有兩個地方調(diào)用了 prepareMainLooper 方法:
第一處是在 SystemServer.java 中的 ServerThread,這個線程是在 Android 啟動過程中的 main() 方法啟動的:
public static void main(String[] args) {
new SystemServer().run();
}
public SystemServer() {
mFactoryTestMode = FactoryTest.getMode();
}
private void run() {
Looper.prepareMainLooper();
Looper.loop();
}
第二處是在 ActivityThread.java 的 main() 方法中:
public static void main(String[] args) {
......
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
Looper.loop();
}
因為systemServer是超級進程娶牌,是在系統(tǒng)啟動的時候,用來初始化各種系統(tǒng)核心服務馆纳,是在不同于APP的進程中的。(從上面的分析來看的話汹桦,Android一個應用開啟對應一個進程鲁驶,一個進程對應有一個主線程。)根據(jù)下圖舞骆,我們可以明白是在App點擊時候的入口钥弯,ActivityThread中對sMainLooper進行賦值的。
3.為什么在子線程創(chuàng)建handler的時候督禽,需要調(diào)用Looper.prepare()方法脆霎?
答:現(xiàn)在我們來看handler的構造方法,對應無Looper形參的構造方法狈惫,都會執(zhí)行下面的構造方法
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
因為在Looper.prepare()會創(chuàng)建一個looper與當前線程綁定睛蛛。如果子線程沒有調(diào)用prepare方法的話,那個mLooper=null,就會出現(xiàn)上面的報錯了忆肾。為什么主線程不需要調(diào)用荸频,從1中我們可以看到,在app進程創(chuàng)建的時候客冈,會調(diào)用Looper.prepareMainLooper(),所以主線程就不用再調(diào)用一次了旭从。
4.當handler發(fā)送一個消息的時候,怎么將消息插到隊列中场仲?
答:如果發(fā)送的是Runnable和悦,不是一個消息,也會在代碼中轉(zhuǎn)成Message類型渠缕,然后最終會執(zhí)行handler的private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)方法:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
將消息插入到消息隊列當中去鸽素。其中的queue是通過looper.mQueue獲取的意味著messageQueue和當前的looper是綁定的,所以一個looper應該是對應一個messageQueue褐健。
5.當Message插入到MessageQueue當中付鹿,系統(tǒng)是怎么通知到對應的handler來執(zhí)行handlerMessage方法呢?
答:如果是在主線程創(chuàng)建Looper的話蚜迅,默認會調(diào)用Looper.loop()方法舵匾,會不停地從消息隊列中取出消息,如果消息隊列為空谁不,則不循環(huán)坐梯,此時釋放cpu,不會占用cpu資源刹帕,如果有消息的話吵血,那就執(zhí)行msg.target.dispatchMessage(msg);實際上就是調(diào)用handler的dispachMessage方法,會調(diào)用handler的handleMessage方法偷溺。
6.在主線程中通過Looper.loop()死循環(huán)蹋辅,為什么不會對主線程造成阻塞呢?
答:因為在該方法中挫掏,Looper在創(chuàng)建的過程中侦另,會創(chuàng)建對應的MessageQueue對象,在構造函數(shù)中尉共,會調(diào)用JNI的方法nativeInit()褒傅,通過這個方法會在c++層創(chuàng)建NativeMessageQueue,同時NativeMessageQueue會創(chuàng)建一個Looper對象袄友,這個Looper對象是通過pipe(管道)設計而成的殿托,如果有消息則喚起讀線程,沒有消息則線程阻塞剧蚣,釋放cpu資源支竹⌒ⅲ回看java層的Looper類的loop方法,Message msg = queue.next()唾戚,進入next方法柳洋,會執(zhí)行nativePollOnce(mPtr, nextPollTimeoutMillis),調(diào)用JNI層的nativePollOnce方法叹坦,會調(diào)用NativeMessageQueue的pollOnce()熊镣,內(nèi)部調(diào)用了c++層Looper對象的pollOnce(),該方法會調(diào)用pollInner()募书,pollInner()方法就是先通過epoll_wait()進入空閑等待狀態(tài)绪囱,等待消息隊列的管道上的消息(IO事件)。如果有消息待處理(即管道上有IO寫事件發(fā)生莹捡,寫事件是EPOLLIN類型)鬼吵,則調(diào)用awoken()將消息讀取出來。所以直到有messageQueue中有消息的時候篮赢,才會喚起齿椅,如果沒有java層沒有消息的時候,線程是會釋放掉cpu資源的启泣;另外所有的ui操作都通過handler來發(fā)消息操作涣脚。
結(jié)論:
1.我們通過handler發(fā)送一個消息,都是通過looper放置對應的messageQueue當中寥茫,然后Looper.loop()會不斷地從messageQueue中獲取消息遣蚀,有消息的話,就通過msg.target(實際就是handler).handlerMessage()纱耻;
2.① 每個Thread只對應一個Looper芭梯;② 每個Looper只對應一個MessageQueue;③ 每個MessageQueue中有N個Message弄喘;④ 每個Message中最多指定一個Handler來處理事件玖喘。一個線程可以擁有多個handler,但是一個handler只能綁定一個線程蘑志。Looper是屬于某一個線程的芒涡,一個looper對應一個MessageQueue。判斷這個handleMessage()方法在哪個線程上執(zhí)行卖漫,就看這個handler的looper對象是在哪個線程,就在這對應的線程上執(zhí)行赠群。
如果有什么不對的羊始,還請指正!