摘要:本文主要說明內部消息機制用模擬進行演示并用圖簡單說明并與生產者與消費者模型進行比對代碼地址需要解決的問題主線程怎樣跟子線程進行通信子線程生產的資源如何傳給主線程子線程如何進行等待完成耗時操作才給主線程傳遞消息為何只能在主線程才能創建子線程想
本文主要說明android內部消息機制,用java模擬進行演示,并用圖簡單說明.并與生產者與消費者模型進行比對;
git代碼地址
需要解決的問題: 1,主線程怎樣跟子線程進行通信,子線程生產的資源,如何傳給主線程? 2,子線程如何進行等待,完成耗時操作才給主線程傳遞消息? 3,為何只能在主線程才能創建handler,子線程想創建該怎么辦? 4,主線程如何與handler/message/looper...進行結合的? 建議帶著問題直接看源碼,放到eclipse或者as或者intellj中實際運行后,理解handler運行原理;1 生產者與消費者模型:
github地址:生產者與消費者
代碼中展示,生產者與消費者是分別是兩個線程,生產或者消耗的資源是num,而Resource3類是個生產線(queue),
通過java的BlockingQueue對生產與消費進行阻塞,最終通過main方法創建線程進行生產與消費;
github代碼
看代碼后理解下圖:
其中子線程的是真正的生產者,把生產后的結果給了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既扮演生產者又是消費者卻只是主線程的對象!3,為何只能在主線程才能創建handler....? 4,主線程如何與handler/message/looper...進行結合的?(通過threadlocal這個map)
handler是通過消息傳遞(message)把json解析出來的東西,傳遞給主線程的messagequeue,然后handler又自己進行處理,這當中handler必須等待子線程生產完成(耗時操作完成);
文章開始提出的第二個問題:2,子線程如何進行等待,完成耗時操作才給主線程傳遞消息? 其中原理不是利用java的blockqueue之類.其中messagequeue是個鏈表,阻塞機制與底層的C++相關聯: 深入理解messagequeue這文章沒有看懂,希望可以拋磚引玉;
另外,handler處理完message之后如何又循環把message填入隊尾的機制也不是很理解;
如下圖解釋:handler為何只能在主線程以及如何保生產消費是同一個handler
其中looper的角色是管理既是管理messagequeue的,又是分發消息給handler的中間者,
handler類圖如下,可見handler中既有looper,又有messagequeue作為成員變量
主線的main方法中有looper.papare(),子線程沒有,給localThread這個map進行設置值:
threadlocal
源碼中,主線程:
在程序啟動的時候,系統已經幫我們自動調用了Looper.prepare()方法。查看ActivityThread中的main()
public static void main(String[] args) { SamplingProfilerIntegration.start(); CloseGuard.setEnabled(false); Environment.initForCurrentUser(); EventLogger.setReporter(new EventLoggingReporter()); Process.setArgV0(""); 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():
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方法的調用流程和使用場景
message入隊的時候可能是按照某種順序直接添加,但是出隊的時候可能是按照子線程生產產品時間最短的先出隊進行處理(或者隊列重排序(個人感覺可能性不大)),這點與生產消費的
模型完全不同,如果按照生產一個,消費一個,生產時間長的排在前面,先來后到的話,生產時間短的排在后面就會一直得不到消費,用戶體驗一定差;
這個時候,一定需要一個電話號碼(message.what),這時候handler就相當于交換機,通知消費者該如何處理,因為子線程的生產時間是隨機,誰也不知道messagequeue排序是如何的,開發者不能根據子線程耗時長短估計處理順序,萬一遇到處理時間相同,消費邏輯不同又該怎么辦,所以一定要用what區分。
一開始感覺安卓完全可以做個標志,類似于msg.what的標志,作為一個map的key直接壓入隊列messagequeue,之后主線程直接取這個get這個標志就可以了,然后自己寫對應的邏輯就可以了,但這會造成在子線程主線程直接與messageQueue進行交互,既要處理子線程間的競爭,這時又要對主線程進行休眠喚醒等操作,對messageQueue的開啟無限循環再get到相應的message,還要處理對子線程的操作,這些復雜的操作都在與主線程的交互sendMessage的時候完成;
當然文章開始提出的那幾個問題沒有完全解決,但是通過這篇文章,能看到安卓中UI線程與子線程交互的巧妙之處;
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/72308.html
摘要:原文地址游客前言金三銀四,很多同學心里大概都準備著年后找工作或者跳槽。最近有很多同學都在交流群里求大廠面試題。 最近整理了一波面試題,包括安卓JAVA方面的,目前大廠還是以安卓源碼,算法,以及數據結構為主,有一些中小型公司也會問到混合開發的知識,至于我為什么傾向于混合開發,我的一句話就是走上編程之路,將來你要學不僅僅是這些,豐富自己方能與世接軌,做好全棧的裝備。 原文地址:游客kutd...
摘要:子線程往消息隊列發送消息,并且往管道文件寫數據,主線程即被喚醒,從管道文件讀取數據,主線程被喚醒只是為了讀取消息,當消息讀取完畢,再次睡眠。因此的循環并不會對性能有過多的消耗。 說下你所知道的設計模式與使用場景 a.建造者模式: 將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。 使用場景比如最常見的AlertDialog,拿我們開發過程中舉例,比如Camera...
閱讀 3137·2021-11-08 13:18
閱讀 2282·2019-08-30 15:55
閱讀 3607·2019-08-30 15:44
閱讀 3067·2019-08-30 13:07
閱讀 2782·2019-08-29 17:20
閱讀 1949·2019-08-29 13:03
閱讀 3410·2019-08-26 10:32
閱讀 3225·2019-08-26 10:15