Android 程序員在面試的時(shí)候被問到頻率最高的就是Handler相關(guān)的問題泣棋,聊到Handler就離不開Looper。那么Android 是如何保證一個(gè)線程對(duì)應(yīng)一個(gè)Looper的呢畔塔。要想弄清楚這個(gè)問題潭辈,我們只能通過源碼找答案。
講這個(gè)問題之前我們先看看Looper是什么時(shí)候創(chuàng)建的澈吨。
Looper的創(chuàng)建
我們都知道Looper的重要性把敢,但是我們?cè)谑褂肏andler發(fā)送和處理消息的時(shí)候會(huì)new一個(gè)Handler,可是為什么沒有new Looper()呢谅辣。
在Activity的主線程中修赞,Looper是被默認(rèn)創(chuàng)建的,所以先來看下ActivityThread源碼桑阶。
圖一:ActivityThread main()源碼
也就是說在我們的主線程被創(chuàng)建的時(shí)候就把Looper()創(chuàng)建好了(6442行) 柏副。
小伙伴們可能有有疑問呢,為什么不是new而是prepare呢蚣录?看下圖大家就明白啦割择!
圖二:Looper 構(gòu)造方法
接下來咱們看看prepareMainLooper()干了什么
圖二:Looper prepareMainLooper()方法??
圖三:?Looper?prepare()方法
圖四:Looper?myLooper()方法
prepare()方法里面判斷了一下如果ThreadLocal get() 不等于空就拋出異常,否則就set一個(gè)Looper()萎河,因此prepare()在同一個(gè)線程里面是不能被調(diào)用兩次的荔泳。
重點(diǎn)來了!E氨玛歌!ThreadLocal 是什么?
我們來看下ThreadLocal都干了啥擎椰。
圖五:?ThreadLocal set()方法??
圖五:?ThreadLocal get()方法??
在set方法里面拿到了當(dāng)前的線程支子,然后獲取了一個(gè)ThreadLocalMap對(duì)象,將當(dāng)前線程作為key达舒,set方法里面的參數(shù)作為value 放到ThreadLoaclMap里面.值朋。
圖六:ThreadLocalMap
圖七:?ThreadLocalMap? set方法
這里set的時(shí)候判斷如果Map里面有的話就替換賦值。get的時(shí)候根據(jù)Thread去拿value(在Looper這就是拿到了Looper 對(duì)象)休弃⊥碳撸看到這里我們標(biāo)題的問題就迎刃而解了圈膏。
Looper在創(chuàng)建的時(shí)候如果有值會(huì)拋出異常塔猾,沒值的時(shí)候就去new,而當(dāng)我們拿Looper的時(shí)候通過當(dāng)前線程鍵值對(duì)去拿稽坤,保證了唯一性丈甸。
好啦糯俗,Looper唯一性就講到這里,小伙伴們聽懂了嗎睦擂?
博主第一次寫專業(yè)知識(shí)講解得湘,喜歡的點(diǎn)個(gè)贊加個(gè)關(guān)注,大家一起進(jìn)步顿仇。(有錯(cuò)誤歡迎指出)