




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、android looper 和 handlermessage:消息,其中包含了消息id,消息處理對象以及處理的數(shù)據(jù)等,由 messagequeue 統(tǒng)一列隊,終由 handler 處理。handler:處理者,負(fù)責(zé)message的發(fā)送及處理。使用handler時,需要實 現(xiàn)handlemessage(message msg)方法來對特定的message進(jìn)彳亍處理,例如更 新ui等。messagequeue:消息隊列,用來存放handler發(fā)送過來的消息,并按照fifo 規(guī)則執(zhí)行。當(dāng)然,存放message并非實際意義的保存,而是將message以 鏈表的方式串聯(lián)起來的,等待looper的抽取。
2、looper:消息泵,不斷地從messagequeue中抽取message執(zhí)彳亍。因此,一 個 messagequeue 需要一個 looper。thread:線程,負(fù)責(zé)調(diào)度整個消息循環(huán),即消息循環(huán)的執(zhí)行場所。android系統(tǒng)的消息隊列和消息循環(huán)都是針對具體線程的,一個線程可以存在(當(dāng)然也可以不存在)一個消息隊列和一個消息循環(huán)(looper),特定線程的消息只能分發(fā)給本線程,不能進(jìn)行跨線程,跨進(jìn)程通訊。但是創(chuàng)建的工作線程 默認(rèn)是沒有消息循環(huán)和消息隊列的,如果想讓該線程具有消息隊列和消息循環(huán), 需要在線程中首先調(diào)用looper.prepare。來創(chuàng)建消息隊歹u,然后調(diào)用looper.loop(
3、) 進(jìn)入消息循環(huán)。如下例所示:class looperthread extends thread public ilem dlcr ml la ndlcr;public void nm() looper, prepare (); 給線程創(chuàng)建一個消息循環(huán) inhandler = new handler () public void handlemessage(message msg) / process incoming messages here;消息注:寫在looper. loop()之后的代碼不會被立即執(zhí)行,當(dāng)調(diào)用后 mhandler. getlooper (). quit ()后,loo
4、p才會中止,其后的代碼才能得以運行。 looper 對象通過 mcssagcqueuc來存放消息和事件。一個線程只能冇一個looper,對應(yīng)一個messagequeue。這樣你的線程就具有了消息處理機制了,在handler中進(jìn)行消息處理。activity是一個ui線程,運行于主線程中,android系統(tǒng)在啟動的時候會為 activity創(chuàng)建一個消息隊列和消息循環(huán)(looper)。詳細(xì)實現(xiàn)請參考 activitythread. java 文件。android應(yīng)用程序進(jìn)程在啟動的時候,會在進(jìn)程中加載activitythread類,并 且執(zhí)行這個類的main函數(shù),應(yīng)用程序的消息循環(huán)過程就是在這個ma
5、in函數(shù)里面 實現(xiàn)的public final class activitythread public static final void main(string args)looper.preparemai nlooper();activitythread thread 二 new activitythread(); thread, attach(false);looper, loop ();thread detacho ;這個函數(shù)做了兩件事情,一是在主線程屮創(chuàng)建了一個activitythread實例,二 是通過looper類使主線程進(jìn)入消息循環(huán)中,這里我們只關(guān)注后者。首先看looper.pr
6、eparemainlooper函數(shù)的實現(xiàn),這是一個靜態(tài)成員函數(shù),定義 在 frameworks/base/core/java/android/os/looper.java 文件中:1 /looper類分析2 沒找到合適的分析代碼的辦法,只能這么來了。毎個重要行的上面都會加 上注釋3 /功能方面的代碼會在代碼前加上一段分析4 public class looper 5 /static變量,判斷是否打印調(diào)試信息。6 private static final boolean debug = false;7 private static final boolean locallogv 二 debug
7、? config. logd :config. logv;89/ sthreadlocal. get() will return null unless you,ve called prepare().10 /線程本地存儲功能的封裝,tls, thread local storage,什么意思呢?因 為存儲要么在棧上,例如函數(shù)內(nèi)定義的內(nèi)部變量。要么在堆上,例如new或者 malloc出來的東西。11 /但是現(xiàn)在的系統(tǒng)比如linux和windows都捉供了線程本地存儲空間,也就 是這個存儲空間是和線程相關(guān)的,一個線程內(nèi)有一個內(nèi)部存儲空間,這樣的話我 把線程相關(guān)的東西就存儲到12 這個線程的tls
8、中,就不用放在堆上而進(jìn)行同步操作了。 /threadlocal并不是一個thread,而是thread的局部變量。13 private static final threadlocal sthreadlocal = new threadloc al 0 ;14 /消息隊列,messagequeue,看名字就知道是個queue.15 final messagequeue mqueue;16 volatile boolcan mrun;17 /和本looper相關(guān)的那個線程,初始化為null18 thread mthread;19 private printer mlogging二 null;20
9、 /static變量,代表一個ui process (也口j能是service吧,這里默認(rèn)就 是ui)的主線程21 private static looper mmainlooper = null;2223public static final void prepare() if (sthreadlocal. get () != null) throw new runtimeexception("only one looper may be cr thread"); sthrcadloca1. set(new looper ();29 往tls中設(shè)上這個looper對象的,
10、如果這個線程已經(jīng)設(shè)過了 looper的話 就會報錯,這說明,一個線程只能設(shè)一個loopero/313233eated per343536 373843 由framework設(shè)置的ut程序的主消息循環(huán),注意,這個主消息循環(huán)是不 會主動退出的444546474849505152535455/public static final void preparemainlooper() prepare ();setmai nlooper(mylooper();判斷主消息循環(huán)是否能退出/通過quit函數(shù)向looper發(fā)出退出申請if (process. supportsprocesses() myloope
11、r(). mqueue. mquitallowed 二 false;private synchronized static void setmainlooper(looper looper)565758mmainlooper 二 looper; 5961 public synchronized static final looper getmainlooper() 62 return mmainlooper;63 646569 消息循環(huán),整個程序就在這里wh訂e 了。70 /這個是static函數(shù)喔!71 public static final void loop() 72 looper me
12、 = mylooper () ;/從該線程屮取出對應(yīng)的looper對象73 messagequeue queue = me. mqueue;/取消息隊列對象.74 wh訂e (true) 75 message msg = queue, next () ; / might block 取消息隊列 中的一個待處理消息76 /if (!me. mrun) /是否需要退lb? mrun 是個 volatile 變 量,跨線程同步的,應(yīng)該是有地方設(shè)置它。7778798081i t message.828384858687888990919293949596/ break;/if (msg != null
13、) if (msg. target 二二 null) / no target is a magic identifier for the qu rcturn;if (me. mlogging!= null) me. mlogging. println(>>>>> dispatching to + msg. target + msg. callback + :+ msg. what);msg.target. dispatchmessage(msg);if (me. mlogging!二 null) me. mlogging. printin(,z<<&l
14、t;<< finished to " + msg. target + "+ msg. callback); msg. recycle ();97101 /返冋和線程相關(guān)的looper102 public static final looper mylooper() 103 rcturn (looper)sthrcadlocal. get();104 105 106115 /設(shè)置調(diào)試輸出對象,looper循環(huán)的時候會打印相關(guān)信息,用來調(diào)試用最 好了。116 public void setmessagelogging(printer printer) 117 mlo
15、gging = printer;118 119120125 public static final messagequeue myqueue() 126 return mylooper(). mqueue;127 128129/創(chuàng)建一個新的looper對彖,/內(nèi)部分配一個消息隊列,設(shè)置mrun為trueprivate looper() mqueue = new messagequeue(); mrun 二 true;mthread = thread. currentthread();publ ic void qui t () message msg = message, obtain();/
16、note: by enqueueing directly into the message queue, t / message is left with a null target. this is how we kn/ a quit message. mqueue. enqueucmcssagc(msg, 0);public thread getthread() return mthread;后面就簡單了,打卬,異常定義等。public void dump(printer pw, string prefix)pw. println(prefix +pw. println(prefix +p
17、w. printin(prefix +this);“mrun二 + mrun);"mthread二"+ mthread);pw. printin(prefix +"mqueue二 + (mqueue != null) ? mqueu(null");if (mqueue !二 nul1) synchronized (mqueue) message msg = mqueue. mmessages;int n = 0; while (msg !二 null) pw. printin(prefix + " message + n + :+n+;msg
18、= msg. next;pw. printin (pref ix + z,(total messages: + n + “)169170public string tostringo 171return "looper172+ tnteger.tohexstring(system, identityhashcode(this)173+ t;174175176static class handlerexception extends exception 177178hemdlerexcepti on(message message, throwable cause) 179super
19、(crcatcmessage(cause),cause);180181182static string createmessage(throwable cause) 183string causemsg = cause. getmessageo ;184if (causemsg 二二 nu11) 185causemsg = cause. tostringo ;186187return causemsg;188189190 那怎么往這個消息隊列中發(fā)送消息呢? ?調(diào)用looper的static函數(shù)myqueue 可以獲得消息隊列,這樣你就可用自己往里邊插入消息了。不過這種方法比較麻 煩,這個時候h
20、andler類就發(fā)揮作用了。先來看看handler的代碼,就明口了。1 class handler2 3 /handler默認(rèn)構(gòu)造函數(shù)4 publ ic handl er () 5 這個if是干嘛用的暫時還不明口,涉及到j(luò)3v3的深層次的內(nèi)容了應(yīng)該6 if (find_potent1al_leaks) 7 final class<? extends handler> klass = getclass ();8 if (klass. isanonymousclass () | | klass. ismemberclass () | | klass. islocalclass() &a
21、mp;&9 (klass. gctmodificrs () & modifier. static) = 0) 10 log. w(tag, "the following handler class should be static or leaks might occur: " +11 klass. getcanonicalname();12 13 14 /獲取本線程的looper對象15 如果木線程述沒有設(shè)置looper,這回拋異常mlooper = looper mylooper (); if (mlooper = null) throw new run
22、timeexception("can't create handler inside thread that has not c looper prepare () ”);16171819ailed2021 /無恥啊,直接把looper的queue和自己的queue搞成一個了22 /這樣的話,我通過handler的封裝機制加消息的話,就相當(dāng)于直接加到了 1 ooper的消息隊列中去了2324252627282930313233mqueue = mlooper .mqueue; mcallback = null;述有好幾種構(gòu)造函數(shù),/由外部設(shè)置looper個是帶callback
23、的,個是帶looper的public ilemdlcr(looper looper) mlooper = looper;mqueue = looper. mqueue; mcallback 二 null;帶 callback 的,一個 handler 可以設(shè)置一個 callback。如果有 callback/的話,34 /凡是發(fā)到通過這個handler發(fā)送的消息,都有callback處理,相當(dāng)于一個 總的集中處理/待會看dispatchmessage的時候再分析public353637383940414243444546474849ilemdlcr(looper looper, callbac
24、k callback) mlooper = looper;mqueue = looper .niqueue;mcallback = callback;/通過handler發(fā)送消息/調(diào)用了 內(nèi)部的一個 sendmessagedelayedpublic final boolean sendmessage(message msg)return sendmessagedelayed(msg, 0);/ft,又封裝了一層,這凹是調(diào)用sendmessageattime 了/因為延時時間是基于當(dāng)前調(diào)用時間的,所以需要獲得絕對時間傳遞給sendmessageattime50 public final bool
25、ean sendmessagedelayed(message msg, long delaymi1 lis)51 52 if (delaymillis < 0) 53 delaymillis 二 0;5859606162636465666768697071);727374757677數(shù)787980818283848586seif (mcallback != null) if (mcallback. handlemessage(msg) return;54 55 return sendmessageattime(msg, systemclockuptimemillis() + delaym
26、illis);56 57 public boolean sendmessageattime(message msg, long uptimemillis)boolean sent 二 false;mcssagcqucuc queue = mqueue; if (queue != null) 把消息的target設(shè)置為自己,然后加入到消息隊列中對于隊列這種數(shù)據(jù)結(jié)構(gòu)來說,操作比較簡單了msg. target 二 this;sent = qucucmcssagc(msg, uptimemillis);else runtimeexception e 二 new runtimeexception(thi
27、s + " sendmessageattime() cal 1ed with no mqueuelog. w("looper", e. getmessage (), e); return sent;/還記得looper中的那個消息循環(huán)處理嗎/從消息隊列屮得到一個消息后,會調(diào)用它的target的dispatchmesage函/message的target已經(jīng)設(shè)置為handler 了,所以/最后會轉(zhuǎn)到handler的msg處理上來這里有個處理流程的問題 public void dispatchmcssagc(message msg) /如果msg本身設(shè)置了 callb
28、ack,則直接交給這個callback處理了if (msg. callback != null) handlecallback(msg); el/如果該handler的callback有的話,則交給這個callback處理了相當(dāng)于集屮處理878889909192 /否則交給派主處理,基類默認(rèn)處理是什么都不干93 handlemessage(msg);94 95 96 97 生成message msg = mhandler.obtainmessage(); msg.what = what;msg.s en dtotargetf);發(fā)送messagequeue queue = mqueue;if
29、(queue != null) msg.target = this;sent = queue.enqueuemessage(msg, uptimemillis);在 handler.java 的 sendmessageattime(message msg, long uptimemillis)方法中,我 們看到,它找到它所引用的messagequeue,然后將message的target設(shè)定成自 己(口的是為了在處理消息環(huán)節(jié),message能找到正確的handler),再將這個 message納入到消息隊列中。抽取looper me = mylooperf);messagequeue queu
30、e = me.mqueue;while (true) message msg = queue.next(); / might block訐(msg != null) if (msg.target = null) / no target is a magic identifier for the quit message, return;msg.target.dispatchmessage(msg);msg.recycled;在looper.java的loop()函數(shù)里,我們看到,這里有一個死循環(huán),不斷地從messagequeue中獲取下一個(next方法)message,然后通過message
31、中攜帶 的target信息,交曲正確的handler處理(dispatchmessage方法)。處理if (msg.callback != null) han dlecallback(msg); else if (mcallback 1= null) if (mcallback.handlemessage(msg) return;han dlemessage(msg);在handler.java的dispatchmessage(message msg)方法里,其中的一個分支就是調(diào) 用handlemessage方法來處理這條message,而這也正是我們在職責(zé)處描述使用 handler 時需要實
32、現(xiàn) handlemessage(message msg)的原因。至于dispatchmessage方法小的另外一個分支,我將會在后而的內(nèi)容小說明。 至此,我們看到,一個message經(jīng)由handler的發(fā)送,messagequeue的入隊, looper的抽取,乂再一次地冋到handler的懷抱。而繞的這一圈,也正好幫助我 們將同步操作變成了異步操作。handler的作用是把消息加入特定的(looper)消息隊列中,并分發(fā)和 處理該消息隊列中的消息。構(gòu)造handler的時候可以指定一個looper 對象,如果不指定則利用當(dāng)前線程的looper創(chuàng)建。詳細(xì)實現(xiàn)請參考 looper的源碼。一個act
33、ivity中可以創(chuàng)建多個工作線程或者其他的組件,如果這些線 程或者組件把他們的消息放入activity的主線程消息隊列,那么該消 息就會在主線程屮處理了。因為主線程一般負(fù)責(zé)界面的更新操作,并且android 系統(tǒng)中的weget不是線程安全的,所以這種方式可以很好的實現(xiàn) android 界面更新。在android系統(tǒng)中這種方式有著廣泛的運用。那么另外一個線程怎樣把消息放入主線程的消息隊列呢?答案是通過 handle對象,只要handler對象以主線程的looper創(chuàng)建,那么調(diào)用handler的sendmessage等接口,將會把消息放入隊列都將是放入主線程的消息隊列。并一且將會在handler主
34、線程中調(diào)用該handler的handlcmessage接口來處理消息。3)剩下的部分,我們將討論一下handler所處的線程及更新ui的方式。在主線程(ui線程)里,如果創(chuàng)建handler吋不傳入looper對象,那么將直接 使用主線程(ui線程)的looper對象(系統(tǒng)已經(jīng)幫我們創(chuàng)建了);在其它線程 里,如果創(chuàng)建handler時不傳入looper對象,那么,這個handler將不能接收處 理消息。在這種情況下,通用的作法是:class looperthread extends thread public handler mhandler;public void run() looper.prepare();mhandler = new handler() public void handlemessage(message msg) / process incoming messages here;loopero op();在創(chuàng)建handler之前,為該線
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 高中英語數(shù)據(jù)驅(qū)動下的跨文化交際能力培養(yǎng)論文
- 初中生心理健康教育課程與學(xué)校心理健康教育資源配置優(yōu)化研究論文
- 花崗巖質(zhì)量管理制度
- 設(shè)計工作室管理制度
- 藏在故宮里的中國史讀書記錄
- 財政結(jié)構(gòu)與人力流動
- 自動判斷閏年
- 山東省東營市廣饒縣2024-2025學(xué)年六年級下學(xué)期期中考試數(shù)學(xué)試題(含部分答案)
- 自動控制升降旗的單片機系統(tǒng)設(shè)計
- 自動控制理論課程教學(xué)大綱
- 河北省部分校2024-2025學(xué)年九年級下學(xué)期開學(xué)測試歷史試題(含答案)
- 智能機器人技術(shù)研發(fā)戰(zhàn)略合作協(xié)議
- 233KWh 定制戶外一體柜儲能系統(tǒng)項目技術(shù)方案
- 2024-2030年中國電船行業(yè)前景展望及投資戰(zhàn)略分析報告
- 2025版國家開放大學(xué)法學(xué)本科《知識產(chǎn)權(quán)法》期末紙質(zhì)考試第三大題名詞解釋題庫
- 保安反恐防暴培訓(xùn)
- 《無人機測繪技術(shù)》項目2任務(wù)1無人機航測任務(wù)規(guī)劃
- 新能源汽車充電樁項目可行性研究報告模板及范文
- 電力市場概論張利課后參考答案
- 2024版首診負(fù)責(zé)制度課件
- 人工智能在教育行業(yè)的創(chuàng)新應(yīng)用研究
評論
0/150
提交評論