本文主要說明android內部消息機制,用java模擬進行演示,並用圖簡單說明.並與生產者與消費者模型進行比對;
git代碼地址html
須要解決的問題: 1,主線程怎樣跟子線程進行通訊,子線程生產的資源,如何傳給主線程? 2,子線程如何進行等待,完成耗時操做纔給主線程傳遞消息? 3,爲什麼只能在主線程才能建立handler,子線程想建立該怎麼辦? 4,主線程如何與handler/message/looper...進行結合的? 建議帶着問題直接看源碼,放到eclipse或者as或者intellj中實際運行後,理解handler運行原理;
github地址:生產者與消費者
代碼中展現,生產者與消費者是分別是兩個線程,生產或者消耗的資源是num,而Resource3類是個生產線(queue),
經過java的BlockingQueue對生產與消費進行阻塞,最終經過main方法建立線程進行生產與消費;java
github代碼
看代碼後理解下圖:android
其中子線程的是真正的生產者,把生產後的結果給了message.obj,而後handler.sendMessage進行入列messagequeue(給了生產線);
@Override public void onResponse(Call call, Response response) throws IOException { final String json = response.body().string(); //Log.e("json", "success: "+json.toString() ); if (null!=json && !"".equals(json)&&(!json.contains("請求錯誤")&&(!json.contains("ConnectionRefused")))) alarmList = GsonUtils.jsonToList(json, Alarm.class); Message message = Message.obtain(); message.what = 0 ; message.obj = alarmList; handler.sendMessage(message); }
以後looper進行dispatch以後,再進行handlerMessage在handler進行消費;可見,android中handler的機制與生產者消費者模型最大區別是生產者消費者分別是兩個線程,而handler既扮演生產者又是消費者卻只是主線程的對象!
handler是經過消息傳遞(message)把json解析出來的東西,傳遞給主線程的messagequeue,而後handler又本身進行處理,這當中handler必須等待子線程生產完成(耗時操做完成);
文章開始提出的第二個問題:2,子線程如何進行等待,完成耗時操做纔給主線程傳遞消息? 其中原理不是利用java的blockqueue之類.其中messagequeue是個鏈表,阻塞機制與底層的C++相關聯: 深刻理解messagequeue這文章沒有看懂,但願能夠拋磚引玉;
另外,handler處理完message以後如何又循環把message填入隊尾的機制也不是很理解;
以下圖解釋:handler爲什麼只能在主線程以及如何保生產消費是同一個handler
其中looper的角色是管理既是管理messagequeue的,又是分發消息給handler的中間者,git
handler類圖以下,可見handler中既有looper,又有messagequeue做爲成員變量
github
主線的main方法中有looper.papare(),子線程沒有,給localThread這個map進行設置值:
threadlocal<T>這個map進行set,其中key=主線程,val=looper(looper又有messagequeue)
源碼中,主線程:
在程序啓動的時候,系統已經幫咱們自動調用了Looper.prepare()方法。查看ActivityThread中的main()json
public static void main(String[] args) { SamplingProfilerIntegration.start(); CloseGuard.setEnabled(false); Environment.initForCurrentUser(); EventLogger.setReporter(new EventLoggingReporter()); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } AsyncTask.init(); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
請注意Looper.prepareMainLooper():eclipse
public static final void prepareMainLooper() { prepare(); //這步至關於對threadlocal進行set,key=主線程,val=looper(looper又有messagequeue) setMainLooper(myLooper()); if (Process.supportsProcesses()) { myLooper().mQueue.mQuitAllowed = false; } }
原理基本結束:其餘的運用以下,道理也是相通的,
理解AsyncTask的源碼
Android:主線程如何向子線程發送消息
至於hander.post()的有不錯的文章:Handler中post方法的調用流程和使用場景ide
message入隊的時候多是按照某種順序直接添加,可是出隊的時候多是按照子線程生產產品時間最短的先出隊進行處理(或者隊列重排序(我的感受可能性不大)),這點與生產消費的
模型徹底不一樣,若是按照生產一個,消費一個,生產時間長的排在前面,先來後到的話,生產時間短的排在後面就會一直得不到消費,用戶體驗必定差;
這個時候,必定須要一個電話號碼(message.what),這時候handler就至關於交換機,通知消費者該如何處理,由於子線程的生產時間是隨機,誰也不知道messagequeue排序是如何的,開發者不能根據子線程耗時長短估計處理順序,萬一遇處處理時間相同,消費邏輯不一樣又該怎麼辦,因此必定要用what區分。oop
一開始感受安卓徹底能夠作個標誌,相似於msg.what的標誌,做爲一個map的key直接壓入隊列messagequeue,以後主線程直接取這個get這個標誌就能夠了,而後本身寫對應的邏輯就能夠了,但這會形成在子線程主線程直接與messageQueue進行交互,既要處理子線程間的競爭,這時又要對主線程進行休眠喚醒等操做,對messageQueue的開啓無限循環再get到相應的message,還要處理對子線程的操做,這些複雜的操做都在與主線程的交互sendMessage的時候完成;post
固然文章開始提出的那幾個問題沒有徹底解決,可是經過這篇文章,能看到安卓中UI線程與子線程交互的巧妙之處;