注:一次OPPO面試的尷尬瓣窄,所以回來(lái)惡補(bǔ)
原文鏈接借鑒
1 HandlerThread
1.1 主要作用
更簡(jiǎn)單的將一個(gè)一次性的多線程改進(jìn)成可以循環(huán)利用的異步線程(個(gè)人理解)
1.2 原理
繼承了Thread述寡,實(shí)際上是一個(gè)使用Looper、Handler的線程圣蝎。
繼承了Thread,在run()方法中通過(guò)Looper.prepare()來(lái)創(chuàng)建消息隊(duì)列栗竖,Looper.loop()來(lái)循環(huán)處理消息猫胁。
使用時(shí)開(kāi)啟HandlerThread,創(chuàng)建Handler與HandlerThread的Looper綁定涣澡,Handler以消息的方式通知HandlerThread來(lái)執(zhí)行一個(gè)具體的任務(wù)贱呐。
1.3 特點(diǎn)
HandlerThread將loop轉(zhuǎn)到子線程中處理,說(shuō)白了就是將分擔(dān)MainLooper的工作量入桂,降低了主線程的壓力奄薇,使主界面更流暢。
開(kāi)啟一個(gè)線程起到多個(gè)線程的作用抗愁。處理任務(wù)是串行執(zhí)行馁蒂,按消息發(fā)送順序進(jìn)行處理。HandlerThread本質(zhì)是一個(gè)線程蜘腌,在線程內(nèi)部远搪,代碼是串行處理的。
但是由于每一個(gè)任務(wù)都將以隊(duì)列的方式逐個(gè)被執(zhí)行到逢捺,一旦隊(duì)列中有某個(gè)任務(wù)執(zhí)行時(shí)間過(guò)長(zhǎng)谁鳍,那么就會(huì)導(dǎo)致后續(xù)的任務(wù)都會(huì)被延遲處理。
HandlerThread擁有自己的消息隊(duì)列劫瞳,它不會(huì)干擾或阻塞UI線程倘潜。
對(duì)于網(wǎng)絡(luò)IO操作,HandlerThread并不適合志于,因?yàn)樗挥幸粋€(gè)線程涮因,還得排隊(duì)一個(gè)一個(gè)等著。
HandlerThread內(nèi)部維護(hù)了一個(gè)消息隊(duì)列伺绽,避免多次創(chuàng)建和銷毀子線程來(lái)進(jìn)行操作养泡。
2 HandlerThread的使用
2.1 HandlerThread使用步驟
(1)創(chuàng)建HandlerThread實(shí)例,參數(shù)字符串定義新線程的名稱奈应。
HandlerThread mHandlerThread =newHandlerThread("check-message-coming");?
(2)啟動(dòng)HandlerThread線程澜掩。
mHandlerThread.start();
(3)創(chuàng)建Handler對(duì)象,將HandlerThread的Lopper作為參數(shù)杖挣,這樣就完成了Handler對(duì)象與HandlerThread的Looper對(duì)象的綁定(這里的Handler對(duì)象可以看作是綁定在HandlerThread子線程中肩榕,所以handlerMessage里的操作是在子線程中運(yùn)行的)。 重寫(xiě)handleMessage處理耗時(shí)操作惩妇。
Handler mCheckMsgHandler =newHandler(mHandlerThread.getLooper()){@OverridepublicvoidhandleMessage(Message msg){// 進(jìn)行耗時(shí)操作}};
這樣我們就可以使用mCheckMsgHandler對(duì)象以處理消息的形式來(lái)進(jìn)行耗時(shí)操作株汉,完成以后就可以切換到主線程的handler中來(lái)更新UI筐乳。
2.2 HandlerThread使用示例
依據(jù)剛才的步驟,來(lái)實(shí)現(xiàn)一個(gè)每秒更新數(shù)據(jù)的一個(gè)功能乔妈,這個(gè)功能可以用來(lái)更新股票蝙云、商品價(jià)格等。
創(chuàng)建和啟動(dòng)HandlerThread路召,handler綁定:新建Activity勃刨,在onCreate()中進(jìn)行使用一個(gè)initBackThread()方法創(chuàng)建HandlerThread。等待mCheckMsgHandler 得到消息開(kāi)始模擬耗時(shí)操作完成后切換到UI線程去更新UI优训,使用主線程的Handler也是一樣的。
綁定按鈕使用handler發(fā)送消息:一個(gè)開(kāi)始按鈕使mCheckMsgHandler發(fā)送消息去進(jìn)行耗時(shí)操作各聘,另一個(gè)按鈕停止發(fā)送消息揣非。標(biāo)記isUpdate設(shè)置是否再次發(fā)送消息更新。
要記得在onPause()和onDestroy()中暫停更新和停止mHandlerThread以釋放內(nèi)存躲因。
具體的源碼分析【轉(zhuǎn)載請(qǐng)注明出處:Android HandlerThread 源碼分析?CSDN 廢墟的樹(shù)】
HandlerThread源碼分析
HandlerThread構(gòu)造函數(shù)
分析:該類開(kāi)頭就給出了一個(gè)描述:該類用于創(chuàng)建一個(gè)帶Looper循環(huán)的線程早敬,Looper對(duì)象用于創(chuàng)建Handler對(duì)象,值得注意的是在創(chuàng)建Handler
對(duì)象之前需要調(diào)用start()方法啟動(dòng)線程大脉。這里可能有些人會(huì)有疑問(wèn)搞监?為啥需要先調(diào)用start()方法之后才能創(chuàng)建Handler呢?后面我們會(huì)解答镰矿。
上面的代碼注釋已經(jīng)很清楚了琐驴,HandlerThread類有兩個(gè)構(gòu)造方法,不同之處就是設(shè)置當(dāng)前線程的優(yōu)先級(jí)參數(shù)秤标。你可以根據(jù)自己的情況來(lái)設(shè)置優(yōu)先
級(jí)绝淡,也可以使用默認(rèn)優(yōu)先級(jí)。
HandlerThread的run方法
分析:以上代碼中的注釋已經(jīng)寫(xiě)得很清楚了苍姜,以上run方法主要作用就是調(diào)用了Looper.prepare和Looper.loop構(gòu)建了一個(gè)循環(huán)線程牢酵。值得一提的
是,run方法中在啟動(dòng)loop循環(huán)之前調(diào)用了onLooperPrepared方法衙猪,該方法的實(shí)現(xiàn)是一個(gè)空的馍乙,用戶可以在子類中實(shí)現(xiàn)該方法。該方法的作用是
在線程loop之前做一些初始化工作垫释,當(dāng)然你也可以不實(shí)現(xiàn)該方法丝格,具體看需求。由此也可以看出棵譬,Google工程師在編寫(xiě)代碼時(shí)也考慮到代碼的可擴(kuò)展性铁追。牛B!
HandlerThread的其他方法
getLooper獲得當(dāng)前線程的Looper對(duì)象
分析:其實(shí)方法開(kāi)頭的英文注釋已經(jīng)解釋的很清楚了:該方法主要作用是獲得當(dāng)前HandlerThread線程中的mLooper對(duì)象。
首先判斷當(dāng)前線程是否存活茫船,如果不是存活的琅束,這直接返回null扭屁。其次如果當(dāng)前線程存活的,在判斷線程的成員變量mLooper是否為null涩禀,如果為
null料滥,說(shuō)明當(dāng)前線程已經(jīng)創(chuàng)建成功,但是還沒(méi)來(lái)得及創(chuàng)建Looper對(duì)象艾船,因此葵腹,這里會(huì)調(diào)用wait方法去等待,當(dāng)run方法中的notifyAll方法調(diào)用之后
通知當(dāng)前線程的wait方法等待結(jié)束屿岂,跳出循環(huán)践宴,獲得mLooper對(duì)象的值。
總結(jié):在獲得mLooper對(duì)象的時(shí)候存在一個(gè)同步的問(wèn)題爷怀,只有當(dāng)線程創(chuàng)建成功并且Looper對(duì)象也創(chuàng)建成功之后才能獲得mLooper的值阻肩。這里等待方法wait和run方法中的notifyAll方法共同完成同步問(wèn)題。
quit結(jié)束當(dāng)前線程的循環(huán)
分析:以上有兩種讓當(dāng)前線程退出循環(huán)的方法运授,一種是安全的烤惊,一中是不安全的。至于兩者有什么區(qū)別? quitSafely方法效率比quit方法標(biāo)率低一點(diǎn)吁朦,但是安全柒室。具體選擇哪種就要看具體項(xiàng)目了。
總結(jié):
1.HandlerThread適用于構(gòu)建循環(huán)線程逗宜。
2.在創(chuàng)建Handler作為HandlerThread線程消息執(zhí)行者的時(shí)候必須調(diào)用start方法之后雄右,因?yàn)閯?chuàng)建Handler需要的Looper參數(shù)是從HandlerThread類中獲得,而Looper對(duì)象的賦值又是在HandlerThread的run方法中創(chuàng)建纺讲。
3.關(guān)于HandlerThread和Service的結(jié)合使用請(qǐng)參考另一篇博客:Android IntentService 源碼分析
【轉(zhuǎn)載請(qǐng)注明出處:Android HandlerThread源碼分析 CSDN 廢墟的樹(shù)】