花樣使用Handler與源碼分析
前幾天在跟公司大佬討論一個(gè)問(wèn)題時(shí),看到他使用Handler的一種方式,旁邊的同事在說(shuō):以前不是這么用的啊。這個(gè)問(wèn)題引發(fā)了我的好奇,雖然當(dāng)時(shí)翻清楚道理了,但是還是想給大家分享一下。
Handler在之前也說(shuō)到過(guò)他的使用以及源碼分析,而且相信大家都知道如何使用它,最常見的使用方法恐怕就是下面這種了:
Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } };
這種情況會(huì)有一個(gè)問(wèn)題:我們都知道Handler是可以用在子線程給主線程更新的,當(dāng)子線程給主線程回調(diào)時(shí),主線程中的Handler通過(guò)接收發(fā)送過(guò)來(lái)的對(duì)應(yīng)消息,去執(zhí)行對(duì)應(yīng)的任務(wù)。而對(duì)于上面這個(gè)Handler對(duì)象,如果他是主線程中的,那么我們子線程中需要拿到主線程的這個(gè)Handler對(duì)象。
final Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; new Thread(new Runnable() { @Override public void run() { handler.sendMessage(new Message()); } }).start();
但是上面這種寫法實(shí)在是太不好看了,而且handler還是一個(gè)局部變量,在其他方法中也無(wú)法使用。
Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.e(TAG, "onCreate: " ); handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; new Thread(new Runnable() { @Override public void run() { handler.sendMessage(new Message()); } }).start(); }
這個(gè)看上去應(yīng)該就好多了,可能也是大多數(shù)人的一種寫法。
其實(shí)說(shuō)白了,如果說(shuō)我們要在子線程中給主線程/相應(yīng)線程回調(diào),那么一定要拿到主線程中的Handler的索引。這么說(shuō)就很直接了,可能有些情況下無(wú)法拿到主線程/相應(yīng)線程的Handler,或者拿到的方法很麻煩:
public class MyService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); new Thread(new Runnable() { @Override public void run() { //執(zhí)行相關(guān)的耗時(shí)操作,然后結(jié)束后通過(guò)Handler回調(diào)給主線程 } }).start(); } }
現(xiàn)在我有這樣的需求:創(chuàng)建一個(gè)服務(wù),在服務(wù)中開啟一個(gè)子線程執(zhí)行耗時(shí)操作,當(dāng)執(zhí)行完畢后回調(diào)在主線程中相應(yīng)。這種情況下想要拿到主線程的Handler對(duì)象也不是不可以,方法還是有很多,把主線程的handler寫成static、創(chuàng)建類繼承Handler并且序列化,然后通過(guò)intent傳入.....可能還有其他的一些方法,但是就目前的這些情況來(lái)看,貌似都不是很友好。下面給大家?guī)?lái)一種比較優(yōu)雅且方便的方法:
public class MyService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); new Thread(new Runnable() { @Override public void run() { /*執(zhí)行相關(guān)的耗時(shí)操作,然后結(jié)束后通過(guò)Handler回調(diào)給主線程*/ new Handler(Looper.getMainLooper()).sendMessage(new Message()); } }).start(); } }
只有一句話:又方便看著又舒服。
(可能有的朋友不知道Looper是什么,本人之前寫過(guò)一篇Handler的文章對(duì)Looper有所介紹,希望對(duì)大家有所幫助:http://www.dbjr.com.cn/article/55386.htm)
通過(guò)Looper.getMainLooper方法,可以獲取到主線程的Looper對(duì)象.
雖然之前說(shuō)我們需要主線程中創(chuàng)建的Handler,其實(shí)嚴(yán)格的說(shuō)是不對(duì)的。究其根本是因?yàn)橹骶€程已經(jīng)為他自己加載了mainLooper,而我們?cè)谥骶€程中new Handler,會(huì)默認(rèn)獲取主線程的Looper引用。
public static void main(String[] args) { //pass Looper.prepareMainLooper(); //pass Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } public Handler(Callback callback, boolean async) { //pass mLooper = Looper.myLooper();//在主線程中new的Handler獲取到的looper就是主線程的mainLooper if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } //pass }
現(xiàn)在看來(lái)就很明確了,在主線程中創(chuàng)建Handler只是個(gè)幌子,真正在背后操縱一切的其實(shí)是looper對(duì)象。所以只需要讓Handler的mLooper引用獲取到主線程的引用就好了。
而且Looper.getMainLooper方法是外部可見的,大膽猜測(cè)這個(gè)方法就是為了這種方便的寫法而存在的。我們可以通過(guò)這個(gè)方法獲取到主線程的looper,讓他實(shí)現(xiàn)主線程中接收回調(diào)。
public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }
但是注意我們上述的這種寫法:new Handler(....).sendMessage
這種寫法不管你怎么去實(shí)現(xiàn),他無(wú)法在主線程得到回應(yīng)(是給大家挖了個(gè)坑哈哈),原因很簡(jiǎn)單:沒(méi)有重寫Handler.handlerMessage方法。
在使用Handler接受消息時(shí)有三種方式:
- 重寫Handler.handlerMessage方法,在該方法中接收
- 在Handler構(gòu)造器中實(shí)現(xiàn)Callback接口,在回調(diào)接口中接收
- 不做任何處理,但是使用post方式發(fā)送消息。
在之前我們Handler接收消息見到的幾乎都是handleMessage方法,其實(shí)這只是其中一種方法,在執(zhí)行該方法之前會(huì)有一個(gè)分發(fā)的方法dispatchMessage:
/** * Handle system messages here. **/ public void dispatchMessage(Message msg) { if (msg.callback != null) {//msg中的callback,這個(gè)是通過(guò)post方法自己封裝的msg(自行查源碼),優(yōu)先級(jí)是最高的 handleCallback(msg); } else {//或者在構(gòu)造器中實(shí)現(xiàn)Handler的Callback接口,這個(gè)優(yōu)先級(jí)第二 if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg);//這才是我們之前最常用的方法,最低的優(yōu)先級(jí) } }
可以看到在handlerMessage方法之前還有兩種回調(diào)的方法。在上述案例中我們并沒(méi)有重寫第三種方法,所以對(duì)于在子線程中匿名使用Handler的情況,我們可以采取上述兩種方案。代碼就不寫了,大家都是聰明人。
好了關(guān)于Handler 的更多使用就到這里了,喜歡的朋友希望多多支持。有不同意見和理解的希望評(píng)論區(qū)多多交流。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
- springmvc中RequestMappingHandlerAdapter與HttpMessageConverter的裝配講解
- ASP.NET Core應(yīng)用錯(cuò)誤處理之ExceptionHandlerMiddleware中間件呈現(xiàn)“定制化錯(cuò)誤頁(yè)面”
- Python中l(wèi)ogging.NullHandler 的使用教程
- Spring MVC學(xué)習(xí)教程之RequestMappingHandlerAdapter詳解
- Spring MVC學(xué)習(xí)教程之RequestMappingHandlerMapping匹配
- MyBatis使用自定義TypeHandler轉(zhuǎn)換類型的實(shí)現(xiàn)方法
- mybatis自定義類型處理器TypehHandler示例詳解
- 深入Android HandlerThread 使用及其源碼完全解析
- 深入Android Handler,MessageQueue與Looper關(guān)系
- .Net WebApi消息攔截器之MessageHandler的示例
相關(guān)文章
Android 中Notification彈出通知實(shí)現(xiàn)代碼
NotificationManager 是狀態(tài)欄通知的管理類,負(fù)責(zé)發(fā)通知、清除通知等操作。接下來(lái)通過(guò)本文給大家介紹Android 中Notification彈出通知實(shí)現(xiàn)代碼,需要的的朋友參考下吧2017-08-08Android實(shí)現(xiàn)簡(jiǎn)易計(jì)算器(可以實(shí)現(xiàn)連續(xù)計(jì)算)
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)簡(jiǎn)易計(jì)算器,可以實(shí)現(xiàn)連續(xù)計(jì)算,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03Android入門之TabHost與TabWidget實(shí)例解析
這篇文章主要介紹了Android入門之TabHost與TabWidget,對(duì)于Android初學(xué)者有一定的學(xué)習(xí)借鑒價(jià)值,需要的朋友可以參考下2014-08-08Android Flutter基于WebSocket實(shí)現(xiàn)即時(shí)通訊功能
WebSocket是一種在單個(gè)TCP連接上進(jìn)行全雙工通信的協(xié)議。本文將利用Flutter WebSocket實(shí)現(xiàn)即時(shí)通訊功能,文中示例代碼講解詳細(xì),感興趣的可以了解一下2022-03-03Android中Progress的簡(jiǎn)單實(shí)例
這篇文章主要介紹了Android中Progress的簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-05-05實(shí)例詳解Android Webview攔截ajax請(qǐng)求
本篇內(nèi)容主要給大家講解了Android Webview攔截ajax請(qǐng)求的詳細(xì)講解,需要的朋友一起來(lái)學(xué)習(xí)一下。2017-11-11Android?進(jìn)入Activity時(shí)如何禁止彈出軟鍵盤輸入法
這篇文章主要介紹了Android?進(jìn)入Activity時(shí)如何禁止彈出軟鍵盤輸入法,文章圍繞主題展開具體內(nèi)容,需要的小伙伴可以參考一下2022-05-05詳解android 人臉檢測(cè)你一定會(huì)遇到的坑
這篇文章主要介紹了詳解android 人臉檢測(cè)你一定會(huì)遇到的坑,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11Android實(shí)現(xiàn)Service下載文件,Notification顯示下載進(jìn)度的示例
本篇文章主要介紹了Android實(shí)現(xiàn)Service下載文件,Notification顯示下載進(jìn)度,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-01-01