您好,登錄后才能下訂單哦!
理解Handler的原理首先要搞清楚什么是Looper,在我的上一篇博文中對此有專門的介紹。Looper的作用是開啟一個消息循環(huán),從MessageQueue(Message隊列,是Looper的成員變量)中循環(huán)取出消息處理。一個線程要使用Handler來處理來自其它線程的消息,這個線程必須有且僅有一個Looper對象與之綁定,也可以說一個Looper對象是是與一個線程一一對應(yīng)的。
Hander有一個Looper類型的成員,在Handler的構(gòu)造函數(shù)(new Handler()或者new Handler(CallBack))中會實例化這個Handler的Looper成員,Handler()構(gòu)造函數(shù)的源碼如下:
public Handler() { //獲得當(dāng)前線程在 ThreadLocal 中所對應(yīng)的 Looper 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 = null; }
在Handler構(gòu)造函數(shù)中實例化的Looper不是通過new關(guān)鍵字來實例化的,而是從Looper.myLooper()這個靜態(tài)方法中取得的。而Looper.myLooper()又是從哪來取得的Looper對象呢?這就涉及到另外一個類ThreadLocal。Looper有一個靜態(tài)變量是ThreadLocal類型的:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
這個變量就是保存每一個線程和這個線程對應(yīng)的Looper。這樣設(shè)計的作用是保證每一個線程的Looper是唯一的。
每一個線程在new Handler()之前必須為這個線程創(chuàng)建Looper對象,使用Looper.prepare()方法創(chuàng)建。
Looper.prepare的源碼如下:
public static void prepare() { //調(diào)用此方法的線程是否在 全局變量 sThreadLocal(即Map<Thread,Looper>)中存有一組以此線程為鍵的鍵值對 if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } //如果在Map<Thread,Looper>中沒有存放當(dāng)前線程對應(yīng)的鍵值對當(dāng)存入 // 一個 set 操作,其實就是在 Map 中插入了一組 <Thread,Looper>值,即 <調(diào)用此方法的線程,new Looper()> // new Looper() 時,Looper的構(gòu)造函數(shù)就會實例化一個 MessageQueue sThreadLocal.set(new Looper());
關(guān)鍵是sThreadLocal.set(new Looper());這條語句,它會把new 出來的Looper保存到ThreadLocal這個全局變量中。
有一個問題,就是為什么我們在主線程中new Handler(){...}之前不需要使用Looper.prepare()呢?因為在主線程執(zhí)行之前,android虛擬機(jī)已經(jīng)幫我們執(zhí)行了這段代碼,因此在主線程中創(chuàng)建Handler對象不需要再新建Looper對象。創(chuàng)建了Handler之后,還要使用Looper.loop()開啟消息循環(huán)來取消息。主線程也不需要這句代碼。
總結(jié):
Looper負(fù)責(zé)開啟消息循環(huán),從MessageQueue中讀取Message,由Handler負(fù)責(zé)處理讀出來的Message。
Looper和它的MessageQueue與某一個線程是一一對應(yīng)的。
使用Handler之前需要使用Looper.prepare()為當(dāng)前線程創(chuàng)建Looper對象。
使用Looper.loop()開啟消息循環(huán)。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。