OUTLINE
§UI線程
§Looper
§消息機(jī)制
§線程交互
§AsyncTask
§Activity/Service與主線程
UI線程
先從一個(gè)經(jīng)典錯(cuò)誤開(kāi)始:
android.view.ViewRootImpl$CalledFromWrongThreadException:
Only the original thread that created a view hierarchy can touch its views
為什么會(huì)出現(xiàn)這個(gè)錯(cuò)誤?
UI的呈現(xiàn)必須在同一個(gè)線程里面完成。
試想,如果多個(gè)線程可以繪制UI,那么肯定亂套,呈現(xiàn)結(jié)果不可預(yù)期。
因此界面程序必然有一個(gè)UI線程,android,java,windows等都是如此。
Android UI 丈量、排布、繪制最終都是在ViewRootImpl里面完成的。
ViewRootImpl在執(zhí)行UI操作之前,會(huì)進(jìn)行線程檢查。如果當(dāng)前線程不是UI線程,就會(huì)拋出上述異常。
每個(gè)應(yīng)用都對(duì)應(yīng)一個(gè)進(jìn)程,進(jìn)程創(chuàng)建是伴隨一個(gè)主線程創(chuàng)建。這個(gè)主線程就是UI線程。
Android的主線線程的入口在ActivityThread。ActivityThread和普通的java入口類(lèi)一樣,有一個(gè)靜態(tài)main函數(shù),作為主線程的入口。
ActivityThread與Android應(yīng)用生命周期密切相關(guān),后續(xù)會(huì)講到。
Looper
Thread是一個(gè)線性執(zhí)行,界面程序需要持續(xù)存在,因此需要一個(gè)循環(huán),Looper就是Android里面線程循環(huán)的封裝。
這樣說(shuō)還是比較抽象,那么Looper到底是什么?
消息機(jī)制

任務(wù)的循環(huán)執(zhí)行,需要一個(gè)隊(duì)列,可進(jìn)可出,Android使用消息隊(duì)列MessageQueue來(lái)實(shí)現(xiàn)。
一個(gè)Looper綁定一個(gè)Thread,在這個(gè)線程中循環(huán);同時(shí)綁定一個(gè)MessageQueue,在這個(gè)消息隊(duì)列中存取消息;然后,通過(guò)Handler向外接口。通過(guò)Handler把消息加入。
MessageQueue, Looper調(diào)用loop進(jìn)行循環(huán),循環(huán)地從消息隊(duì)列中獲取消息,處理消息。
Message
§消息出隊(duì):MessageQueue::next
§消息入隊(duì)<- 生成消息:綁定Handler
? ?Handler::obtainMessage
?? Message::obtainMessage(Handler)
消息隊(duì)列中的消息是供Looper來(lái)消耗的,Looper通過(guò)MessageQueue的next方法取出消息。這個(gè)過(guò)程是在Looper內(nèi)部完成,我們不需要太過(guò)關(guān)心。
不過(guò)next方法也是比較講究的,這個(gè)方法最終會(huì)調(diào)用native的方法,可能會(huì)等待睡眠,直到IO事件或者消息入隊(duì)把它喚醒。
Android的Message必須綁定到一個(gè)Handler,由這個(gè)Handler來(lái)發(fā)送和處理消息。消息入隊(duì)的時(shí)候會(huì)檢查消息是否綁定了Handler,如果沒(méi)有綁定,會(huì)直接拋出異常。
因此我們通常是Handler::obtainMessage,這個(gè)方法獲得的Message直接綁定到了Handler;另外,也會(huì)Message::obtainMessage,當(dāng)前必須傳遞Handler。
Looper的創(chuàng)建
§Looper.prepare生成Looper實(shí)例
§ThreadLocal映射,將Looper和Thread綁定
Looper.prepare();
?Looper looper = Looper.myLooper();
?...
?Looper.loop();
在線程中調(diào)用Looper.prepare完成Looper的創(chuàng)建。
通過(guò)ThreadLocal映射,Looper與線程綁定。
Looper創(chuàng)建時(shí)生成了MessageQueue。
Thread和ThreadLocal都是java的東西,Looper是Android的。Thread和Looper之前的綁定使用了ThreadLocal。ThreadLocal就是線程的存儲(chǔ)器,它是一個(gè)通用設(shè)計(jì),它為每個(gè)線程存儲(chǔ)數(shù)據(jù),從每個(gè)線程進(jìn)來(lái)看到對(duì)應(yīng)的線程的數(shù)據(jù)。因此Android的Looper很好地利用了這一點(diǎn),使用ThreadLocal,從每個(gè)線程進(jìn)來(lái)看到的Looper都是綁定的Looper。
MainLooper的創(chuàng)建
§ActivityThread main入口
?Looper. prepareMainLooper();
?...
?Looper.loop();
主線程入口處(ActivityThread的main入口),調(diào)用Looper.prepareMainLooper,完成MainLooper的創(chuàng)建。再調(diào)用loop讓主線程循環(huán)起來(lái)。
MainLooper作為靜態(tài)變量保存在Looper中,可通過(guò)getMainLooper獲取。
?Handler的創(chuàng)建
§Handler——Looper的對(duì)外接口
§Handler創(chuàng)建 <- Looper實(shí)例
?主線程Handler:直接獲取MainLooper來(lái)創(chuàng)建。
?其他線程Handler:必須在調(diào)用Looper.prepare之后創(chuàng)建。
eg:
HandlerThread::onLooperPrepared
?不指定Looper,使用當(dāng)前線程Looper。
Handler創(chuàng)建需要指定Looper,因此Handler的創(chuàng)建需要在調(diào)用Looper.prepare之后(HandlerThread.onLooperPrepared),否則會(huì)報(bào)異常。
如果沒(méi)有Looper,默認(rèn)使用當(dāng)前線程綁定的Looper。
因此,通常在主線程可以任意創(chuàng)建Handler,因?yàn)镸ainLooper在主線程啟動(dòng)時(shí)已經(jīng)prepare。
而在其他線程創(chuàng)建Handler時(shí)需要先調(diào)用Looper.prepare。
非主線線程Handler典型創(chuàng)建方法是通過(guò)HandlerThread。HandlerThread是Android聯(lián)結(jié)Handler和線程的封裝,它用onLooperPrepared回調(diào)提供給外界創(chuàng)建Handler。
?線程的創(chuàng)建
§線性執(zhí)行:直接或間接new Thread
§循環(huán):
?????????????? 1. 基于Looper的Thread ->HandlerThread
?????????????? 2. 自己為線程實(shí)現(xiàn)循環(huán)機(jī)制
線程交互
線程之間的交互通過(guò)消息機(jī)制完成。具體來(lái)說(shuō),A線程需要發(fā)送消息到B線程,需要通過(guò)持有B線程Looper的Handler發(fā)送消息。
eg:? A線程需要操作B線程
A發(fā)送消息給B
?A發(fā)送:A需要Handler實(shí)例
?給B:Handler實(shí)例必須持有B線程的Looper。
實(shí)現(xiàn):
?B線程生成Handler
?Handler定義消息和消息處理
主線程與非主線程交互
§主線程執(zhí)行非主線程操作
?獲取非主線程Handler發(fā)送消息。?? ? 針對(duì)持久存在的非主線程處理
?通過(guò)AsyncTask::doInBackground執(zhí)行。 針對(duì)臨時(shí)存在的后臺(tái)線程處理
-View.post(Runnable)。 ? ? 在View中執(zhí)行。
-Activity.runOnUiThread。 ? ? 在Activity中執(zhí)行。
§非主線程執(zhí)行主線程操作
?獲取MainLooper生成主線程Handler。 ?針對(duì)持久的主線程處理
?eg:ViewRootHander,Activity的Handler
?通過(guò)AsyncTask::onProgressUpdate或onPostExecute。 ? 針對(duì)臨時(shí)主線程處理
?通過(guò)臨時(shí)new Handler(傳遞MainLooper)來(lái)post執(zhí)行。
View的post函數(shù)將Runnable加入到ViewRootImpl的執(zhí)行隊(duì)列中,在下次ViewRootImpl執(zhí)行tranversal時(shí),將隊(duì)列任務(wù)加入一個(gè)主線程的Handler的消息隊(duì)列。
Activity的runOnUiThread后文再詳細(xì)講解。
AsyncTask是Android對(duì)主線程和后臺(tái)線程處理的一個(gè)封裝,它是線性執(zhí)行的,不作循環(huán)。
AsyncTask
§主線程執(zhí)行——持有MainLooper的Handler靜態(tài)成員sHandler,在主線程入口處初始化。
§后臺(tái)執(zhí)行——新建線程,設(shè)置為優(yōu)先級(jí):
THREAD_PRIORITY_BACKGROUND
onProgressUpdate
onPostExecute? 主線程
doInBackground???? 后臺(tái)線程
onPreExecute????? 取決于調(diào)用線程
AsyncTask持有一個(gè)靜態(tài)Handler,由主線程入口處初始化創(chuàng)建,因此它持有MainLooper。onProgressUpdate和onPostExecute是通過(guò)該Handler執(zhí)行的,因此都是主線程操作。
類(lèi)的靜態(tài)成員和靜態(tài)塊,是在類(lèi)加載的時(shí)候執(zhí)行的。在主線程入口的地方,沒(méi)有必須創(chuàng)建一個(gè)AsyncTask實(shí)例,但是需要為它初始Handler,因此調(diào)用AsyncTask一個(gè)無(wú)用的靜態(tài)方法init,僅僅是為了初始化Handler。
AsyncTask的后臺(tái)執(zhí)行是通過(guò)創(chuàng)建一個(gè)新的線程,非設(shè)置線程優(yōu)先級(jí)為Background,因此它執(zhí)行后臺(tái)操作。
onProgressUpdate和onPostExecute是通過(guò)該Handler執(zhí)行的,因此都是主線程操作。doInBackground是新建線程(THREAD_PRIORITY_BACKGROUND優(yōu)先級(jí)),因此是后臺(tái)線程操作。onPreExecute在execute中執(zhí)行,所在線程取決于調(diào)用的線程。
線程優(yōu)先級(jí)
§設(shè)置線程優(yōu)先級(jí)
?android.os.Process.setThreadPriority:[-20, 19]。越小優(yōu)先級(jí)越高
?java.lang.Thread.setPriority:[1, 10]。越大優(yōu)先級(jí)越高。
§THREAD_PRIORITY_BACKGROUND(10):標(biāo)準(zhǔn)的后臺(tái)優(yōu)先級(jí)
§默認(rèn)線程優(yōu)先級(jí):THREAD_PRIORITY_DEFAULT(0),中等
設(shè)置線程優(yōu)先級(jí)有兩種方式:
android.os.Process.setThreadPriority:[-20,19]。越小優(yōu)先級(jí)越高
java.lang.Thread.setPriority:[1, 10]。越大優(yōu)先級(jí)越高。
優(yōu)先級(jí)調(diào)度是底層實(shí)現(xiàn)的,沒(méi)有具體深入。優(yōu)先級(jí)的設(shè)置和執(zhí)行結(jié)果是沒(méi)有辦法準(zhǔn)確預(yù)期的,但是可以肯定的是Process.setThreadPriority的效果更符合預(yù)期。
Activity/Service與主線程
§Activity和Service運(yùn)行在主線程(ActivityThread$H)
?onCreate,onResume,…
§Activity Handler
?與AsyncTask類(lèi)似,Activity內(nèi)部有一個(gè)持有MainLooper的Handler。
Acitivty的啟動(dòng)過(guò)程是通過(guò)ActivityThread.H這樣一個(gè)Handler來(lái)調(diào)用的,這是一個(gè)主線程的Handler,因此主線程的啟動(dòng)都在主線程。
另外,與AsyncTask類(lèi)似,Activity內(nèi)部有一個(gè)持有MainLooper的Handler。因此Activity提供了一個(gè)runOnUiThread的方法,方便直接執(zhí)行UI操作。