(原)Android在子線程用handler發送的消息,主線程是怎么loop到的?


 
大家都知道Android的Looper是ThreadLocal方式實現,每個線程對應自己的Looper和MessageQueeu。假如我在子線程thread1中用handler.sendEmptyMessage(1)發了個消息,按源碼的理解是把消息發送到了thread1線程的MessageQueue里。

另一方面,來看運行在main線程的handleMessage,調用它的地方是Handler的dispatchMessage,再往上推是Looper的loop方法調的handler的dispatchMessage,所以如果沒猜錯的話loop方法應該是main線程。
那問題來了,不是各個線程管理各自的MessageQueue嗎?那運行在main線程的loop方法是怎么拿到我發到thread1的MessageQueue並處理它里邊的Message的呢?

求大神解答,是我哪兒理解不對嗎?
 
 
張崢超  軟件工程師
你的理解有問題。。。不是各個線程管理各自的MessageQueue。而是各個線程都去獲取了主線程的LOOP和MessageQueue
 
 
 
離苦得樂  眾生皆苦
首答。手頭沒有源碼,就按着自己的記憶和理解來“霸王硬上弓”了,水平有限,如有偏差或錯誤,請大神們不吝指教!
首先,Handler,Looper,MessageQueue這三者如何關聯的?這里拿最簡單的new 一個無參Handler為例。在創建無參的Handler時會對其中變量MessageQueue賦值,這個值就是Looper對象的MessageQueue,那么這個Looper對象又是在那創建的呢?如果是在app進程中的話,在啟動該app時會調用ActivityThread,main方法進入主線程,在main函數中會有初始化Looper,並調用looper.loop()輪詢MessageQueue中的Message,這個Message是handler在調用sendMessage或者post時會將Message enqueue到MessageQueue中,這樣Looper 就會loop 到Handler發送到MessageQueue中的Message,loop時就會dispatchMessage了,再然后就是Hanlder處理message了,在調用sendMessage時,handler必須要重寫handleMessage方法。這樣就完成了發送消息和處理消息。在app的進程中,thread1還是發送消息到主線程中的MessageQueue,這個MessageQueue在首次啟動app時就在創建Looper時已經創建好了。那么如果不是在app進程怎么辦呢?假如是在ActivityManagerService中使用Handler的話呢?ActivityManagerService可以理解為在system_server進程中的一個線程,在啟動system_server時並沒有像啟動一個app進程那樣系統已經創建好了Looper,那么我們如果要使用Handler機制,就必須要有Handler,Looper,MessageQueue,Message,一來我們可以自己手動調用Looper.prepare和Looper.loop,另外,系統也已經封裝好了,就是HandlerThread。HandlerThread是一個Thread,在里面已經將Looper,MessageQueue准備好了,這時候創建Handler時,將HandlerThread的Looper傳給Handler就行了,這樣Handler,Looper,MessageQueue就都有了,就可以利用Handler機制進行線程間通信了。
 
 
西米  android framework/native, kernel. etc
贊同樓上的看法。
1.主線程是 有且僅有一個Looper對象, Looper對象里又有一個MessageQueue。
2. Looper 負責不停的loop,並調用Handler的handleMessage處理Message。
3. Handler 負責投遞message, 以及提供處理消息的方法handleMessage。
4 任何非主線程, 想要給 主線程發message, 必須通過handler(該handler內部包含了主線程的Looper引用)
擴展下:
不只是涉及主線程, 任意 子線程之間要傳遞異步消息的話,也可以用handler, 該handler中引用的looper對象是屬於那個線程的, 就會把消息投遞給該線程, 並在該線程里執行 handleMessage方法。 
請參考 Handler的幾個構造方法。
 
 
 
楊強  android開發
剛解決了
由於Handler是在主線程中new的,而Handler的構造函數中才給其成員變量mLooper賦的值:mLooper = Looper.myLooper();所以說在子線程中send的Message其實也是發到了main線程
 
 
=============================================================================================================================
lihaiping: 上述幾位兄弟的回答,讓我也算是完全明白了,handler是如何切換線程的,並進行線程間通信的了。
這里先把我個人的理解寫下來:
所謂的在子線程通過handle發送消息,然后回主線程處理消息,通過handleMessage進行UI的更新,這個例子其實很常見,就是在主線程中我們通過創建一個mainHandler對象,然后並重寫這個handler的handleMessage函數,並在子線程中通過主線程中創建的這個mainHandler來發送消息給主線程。
其實在主線程中創建的這個mainHandler,他在new的時候,就會自動的和主線程中的looper對象進行綁定,而looper對象里只有一個messageQueue,所以這樣3者就建立了聯系。同時主線程中的Looper會不停的loop,在這個loop函數里面他會不斷的取looper對象里面的MessageQueue中的massage,然后調用消息目標(發送消息的handler)的handleMessage。其實這一切都是在主線程下執行的,所以才能進行UI的更新。
那么在 子進程中發送消息,其實只是在子線程中引用了mainHander這個handler對象,並調用該handler對象的sendMessage函數發送消息,而發送消息函數sendMessasge函數所做的事情,是將需要發送出去的這個message放入handler對象的消息隊列中,就完事了。注意:這里的發送消息,僅僅是將消息入隊到調用發送消息的那個handler對象的消息隊列中,而不是調用發送消息的這個子線程的消息隊列中。

例如mainHandler.sendEmptyMessage(0)這個函數,他入隊消息的隊列是mainHandler對應的MessageQueue中,跟調用發送消息的隊列無關。

 
 
對於線程的切換,調度那就是系統的事情了。他什么時候調用主線程,調用子線程,是系統任務調度的問題。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM