1.Android中為什么主線程不會(huì)因?yàn)長ooper.loop()里的死循環(huán)卡死?
2.沒看見哪里有相關(guān)代碼為這個(gè)死循環(huán)準(zhǔn)備了一個(gè)新線程去運(yùn)轉(zhuǎn)?
3.Activity的生命周期這些方法這些都是在主線程里執(zhí)行的吧,那這些生命周期方法是怎么實(shí)現(xiàn)在死循環(huán)體外能夠執(zhí)行起來的?
--------------------------------------------------------------------------------------------------------------------------------------
(1) Android中為什么主線程不會(huì)因?yàn)長ooper.loop()里的死循環(huán)卡死?
這里涉及線程,先說說說進(jìn)程/線程,進(jìn)程:每個(gè)app運(yùn)行時(shí)前首先創(chuàng)建一個(gè)進(jìn)程,該進(jìn)程是由Zygote fork出來的,用于承載App上運(yùn)行的各種Activity/Service等組件。進(jìn)程對(duì)于上層應(yīng)用來說是完全透明的,這也是google有意為之,讓App程序都是運(yùn)行在Android Runtime。大多數(shù)情況一個(gè)App就運(yùn)行在一個(gè)進(jìn)程中,除非在AndroidManifest.xml中配置Android:process屬性,或通過native代碼fork進(jìn)程。
線程:線程對(duì)應(yīng)用來說非常常見,比如每次new Thread().start都會(huì)創(chuàng)建一個(gè)新的線程。該線程與App所在進(jìn)程之間資源共享,從Linux角度來說進(jìn)程與線程除了是否共享資源外,并沒有本質(zhì)的區(qū)別,都是一個(gè)task_struct結(jié)構(gòu)體,在CPU看來進(jìn)程或線程無非就是一段可執(zhí)行的代碼,CPU采用CFS調(diào)度算法,保證每個(gè)task都盡可能公平的享有CPU時(shí)間片。
有了這么準(zhǔn)備,再說說死循環(huán)問題:
對(duì)于線程既然是一段可執(zhí)行的代碼,當(dāng)可執(zhí)行代碼執(zhí)行完成后,線程生命周期便該終止了,線程退出。而對(duì)于主線程,我們是絕不希望會(huì)被運(yùn)行一段時(shí)間,自己就退出,那么如何保證能一直存活呢?簡單做法就是可執(zhí)行代碼是能一直執(zhí)行下去的,死循環(huán)便能保證不會(huì)被退出,例如,binder線程也是采用死循環(huán)的方法,通過循環(huán)方式不同與Binder驅(qū)動(dòng)進(jìn)行讀寫操作,當(dāng)然并非簡單地死循環(huán),無消息時(shí)會(huì)休眠。但這里可能又引發(fā)了另一個(gè)問題,既然是死循環(huán)又如何去處理其他事務(wù)呢?通過創(chuàng)建新線程的方式。
真正會(huì)卡死主線程的操作是在回調(diào)方法onCreate/onStart/onResume等操作時(shí)間過長,會(huì)導(dǎo)致掉幀,甚至發(fā)生ANR,looper.loop本身不會(huì)導(dǎo)致應(yīng)用卡死。
(2) 沒看見哪里有相關(guān)代碼為這個(gè)死循環(huán)準(zhǔn)備了一個(gè)新線程去運(yùn)轉(zhuǎn)?
事實(shí)上,會(huì)在進(jìn)入死循環(huán)之前便創(chuàng)建了新binder線程,在代碼ActivityThread.main()中:
public static void main(String[] args) {
....
//創(chuàng)建Looper和MessageQueue對(duì)象,用于處理主線程的消息
Looper.prepareMainLooper();
//創(chuàng)建ActivityThread對(duì)象
ActivityThread thread = new ActivityThread();
//建立Binder通道 (創(chuàng)建新線程)
thread.attach(false);
Looper.loop(); //消息循環(huán)運(yùn)行
throw new RuntimeException("Main thread loop unexpectedly exited");
}
thread.attach(false);便會(huì)創(chuàng)建一個(gè)Binder線程(具體是指ApplicationThread,Binder的服務(wù)端,用于接收系統(tǒng)服務(wù)AMS發(fā)送來的事件),該Binder線程通過Handler將Message發(fā)送給主線程
另外,ActivityThread實(shí)際上并非線程,不像HandlerThread類,ActivityThread并沒有真正繼承Thread類,只是往往運(yùn)行在主線程,該人以線程的感覺,其實(shí)承載ActivityThread的主線程就是由Zygote fork而創(chuàng)建的進(jìn)程。
主線程的死循環(huán)一直運(yùn)行是不是特別消耗CPU資源呢? 其實(shí)不然,這里就涉及到Linux pipe/epoll機(jī)制,簡單說就是在主線程的MessageQueue沒有消息時(shí),便阻塞在loop的queue.next()中的nativePollOnce()方法里,詳情見Android消息機(jī)制1-Handler(Java層),此時(shí)主線程會(huì)釋放CPU資源進(jìn)入休眠狀態(tài),直到下個(gè)消息到達(dá)或者有事務(wù)發(fā)生,通過往pipe管道寫端寫入數(shù)據(jù)來喚醒主線程工作。這里采用的epoll機(jī)制,是一種IO多路復(fù)用機(jī)制,可以同時(shí)監(jiān)控多個(gè)描述符,當(dāng)某個(gè)描述符就緒(讀或?qū)懢途w),則立刻通知相應(yīng)程序進(jìn)行讀或?qū)懖僮?,本質(zhì)同步I/O,即讀寫是阻塞的。 所以說,主線程大多數(shù)時(shí)候都是處于休眠狀態(tài),并不會(huì)消耗大量CPU資源。
(3) Activity的生命周期是怎么實(shí)現(xiàn)在死循環(huán)體外能夠執(zhí)行起來的?
ActivityThread的內(nèi)部類H繼承于Handler,通過handler消息機(jī)制,簡單說Handler機(jī)制用于同一個(gè)進(jìn)程的線程間通信。
Activity的生命周期都是依靠主線程的Looper.loop,當(dāng)收到不同Message時(shí)則采用相應(yīng)措施:
在H.handleMessage(msg)方法中,根據(jù)接收到不同的msg,執(zhí)行相應(yīng)的生命周期。
比如收到msg=H.LAUNCH_ACTIVITY,則調(diào)用ActivityThread.handleLaunchActivity()方法,最終會(huì)通過反射機(jī)制,創(chuàng)建Activity實(shí)例,然后再執(zhí)行Activity.onCreate()等方法;
再比如收到msg=H.PAUSE_ACTIVITY,則調(diào)用ActivityThread.handlePauseActivity()方法,最終會(huì)執(zhí)行Activity.onPause()等方法。 上述過程,我只挑核心邏輯講,真正該過程遠(yuǎn)比這復(fù)雜。
主線程的消息又是哪來的呢?當(dāng)然是App進(jìn)程中的其他線程通過Handler發(fā)送給主線程,請(qǐng)看接下來的內(nèi)容:
--------------------------------------------------------------------------------------------------------------------------------------
最后,從進(jìn)程與線程間通信的角度,通過一張圖加深大家對(duì)App運(yùn)行過程的理解:
App進(jìn)程則是我們常說的應(yīng)用程序,主線程主要負(fù)責(zé)Activity/Service等組件的生命周期以及UI相關(guān)操作都運(yùn)行在這個(gè)線程; 另外,每個(gè)App進(jìn)程中至少會(huì)有兩個(gè)binder線程 ApplicationThread(簡稱AT)和ActivityManagerProxy(簡稱AMP),除了圖中畫的線程,其中還有很多線程,比如signal catcher線程等,這里就不一一列舉。
Binder用于不同進(jìn)程之間通信,由一個(gè)進(jìn)程的Binder客戶端向另一個(gè)進(jìn)程的服務(wù)端發(fā)送事務(wù),比如圖中線程2向線程4發(fā)送事務(wù);而handler用于同一個(gè)進(jìn)程中不同線程的通信,比如圖中線程4向主線程發(fā)送消息。
結(jié)合圖說說Activity生命周期,比如暫停Activity,流程如下: