Handler我們都知道,它需要和Looper綁定,當Handler在主線程創建,則會默認綁定主線程的Looper,當是在子線程創建,則需要在Handler的構造方法里傳入子線程的Looper的對象。
Handler mHandler;Thread worker = new Thread(){ @Override public void run() { Looper.prepare(); mHandler = new Handler(Looper.myLooper()){ @Override public void handleMessage(Message msg) { ... } }; Looper.loop(); }};private void sendMessage(Object obj){ Message msg = new Message(); msg.obj = obj; mHandler.sendMessage(msg);}
上面是在子線程創建一個Handler的demo,通過這個Handler我們可以把消息發送到子線程,讓子線程去進行對應的操作。其實到這里只是知道如何用Handler和Looper來實現線程通信,想知道真正的原理,還需要看Looper的源碼。
我們先來看看Looper的構造方法,
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread();}
所以Looper其實不暴露構造方法給外部,只通過 prepare()給外部調用,我們再看看prepare()方法
public static void prepare() { prepare(true);}private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed));}
到這里就可以看出來,Looper通過public的prepare()方法,構造了一個Looper對象,并保存在sThreadLocal中。我們在不同線程里創建的所有Looper都會保存在它里面。下面是sThreadLocal在Looper里的代碼,
// sThreadLocal.get() will return null unless you've called prepare().static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
每當我們用 Looper.myLooper()獲取當前線程的Looper時,就會從 sThreadLocal 中獲取。這里涉及到一個有趣的東西,ThreadLocal的使用保證了當前線程只能獲取到當前線程創建的Looper,這是ThreadLocal的特性。
當我們調用Looper.loop()之后,當前線程對應的Looper就會循環不斷的從MessageQueue中拿消息,并扔給Handler去處理,回過頭來看Looper的構造方法,就可以看到MessageQueue對象了。
最后我們再簡單看一下Looper.loop()的代碼,
public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; ... for (;;) { Message msg = queue.next(); // might block ... try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } ... }}
到這里就明白,其實Loop就是開始一個無限循環,并從當前線程的Looper里去獲取MessageQueue,然后從中讀取Message并分發給Handler的過程。當然這里面還有其他幾個細節,我們留著下次繼續分析,比如1 既然loop()是個無限循環,它為什么不會造成資源無限消耗2 ThreadLocal是怎么做到當前線程只能獲取到它自己的Looper的
Looper的原理可以總結如下,· 每個線程都可以創建一個Looper,它會保存在當前線程對應的ThreadLocal里· Handler需要綁定對應線程的Looper對象· 線程在創建完Looper后,需要調用Looper.loop()以讓它循環的去讀取并分發消息· 跟Looper綁定的Handler會在接收到消息后在對應的線程里處理消息
以上就是Android線程交互的原理啦,希望下次面試遇到這個問題時能有幫助~
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
網絡推廣與網站優化公司(網絡優化與推廣專家)作為數字營銷領域的核心服務提供方,其價值在于通過技術手段與策略規劃幫助企業提升線上曝光度、用戶轉化率及品牌影響力。這...
在當今數字化時代,公司網站已成為企業展示形象、傳遞信息和開展業務的重要平臺。然而,對于許多公司來說,網站建設的價格是一個關鍵考量因素。本文將圍繞“公司網站建設價...
在當今的數字化時代,企業網站已成為企業展示形象、吸引客戶和開展業務的重要平臺。然而,對于許多中小企業來說,高昂的網站建設費用可能會成為其發展的瓶頸。幸運的是,隨...
草缸里不放蝦屋可以嗎?蝦屋大概有兩個作用,一是提供遮擋,二是模仿自然環境,滿足愛躲避的蝦的生活習慣,所以可以處于更好的狀態,供觀賞蝦使用。如果缸里沒有吃蝦的魚,又不是觀賞蝦,那就根本不需要蝦舍。如果是觀賞蝦,如果營造水草、沉木等密集區域,其實比蝦房營造更暗的棲息地更好,蝦房里買的蝦不一定能進去。在草缸里既養熱帶魚又養蝦的話,蝦會被吃嗎?用準備蝦窩嗎?1 .成年蝦不會吃,幼蝦會吃(指小魚)。2.如果...
北京十中初中部怎么樣?第十中學非常好。其校長知名度高于官校,但在學校的教育理念和精耕細作上頗有建樹。是中央和各大部委選送的學校,共建單位都很優秀。是東城區最好的中學,生源出口比較理想。是一所與主流社會緊密相連的小學,外語教學特色令人印象深刻,令人羨慕。北京十中初中部怎么樣?在豐臺排名第三。我從初一開始就在十中讀書,現在高中還在十中。我覺得十中初中部比高中好。高三實驗班還可以,普通班就沒那么好了。另...
誰有《玻璃杯》歌詞?玻璃演唱:Cremebrulee組合你曾說我的心像玻璃。要像水一樣透明,哪怕滿是心碎。你可以很輕松的撒出來,假裝無所謂。我常說我就像一面玻璃。心痛,無愿,無悔,再灑脫,再美好的笑。我該為我破碎的心付出什么?嘿,一小杯裝不下太多眼淚多一點愛會讓你更累。撒一些,讓自己飛起來。輕輕敲打的玻璃總是太容易破碎。眼淚裝不下魅力。誰殲滅了誰,誰能理解?你曾說我的心像玻璃。要像水一樣透明,哪怕...