首先我們要知道Handler是幹什麼的?
handler主要是用於子線程和主線程之間進行數據交互(通信)。當需要有耗時操作(HTTP請求,數據庫訪問等),我們在子線程完成這些操作,而完成之後通過handler來進行 通信,下面我們來看一下handler的使用:
在MainActivity中創建一個handler對象。
寫一個按鈕
在上面定義的but方法中,用handler發送一條信息,
然後我們回到handler中,接收這個message
好了,我們來看一下他的效果
這是在主線程中使用handler,下面我們來看一下在子線程中是怎麼樣使用的:
定義個新的按鈕,
在點擊事件中創建一個新的線程,並且在線程裏面對一個handlerThread初始化。
大家注意到沒,在子線程中,多了兩個方法Looper.prepare()和Looper.loop();兩個方法。這個如果在子線程中使用Handler必須要寫這兩個方法,至於原因我們等一會兒再說。
然後我們分別用handlerThread和handler發送一條消息,
爲了看的明顯,我們延時了3秒。
接着我們寫handlerThread中的handleMessage方法。
好了,我們來跑一下,看看效果:
好了, 這是handler的兩種用法,我們已經學會了。
大家還記得剛纔我們在子線程多加的兩個方法嗎?Looper.prepare()和Looper.loop();這兩個方法是必須要執行的,因爲不是我們主線程不用執行,而是主線程已經自動幫我們執行了這兩個方法了,我們進入main方法看一下:
我們注意到綠色方框框起來的兩個方法正是Looper.prepare()和Looper.loop()。
那麼這兩個方法到底是幹嘛的呢?不要着急,我們首先來看一下Handler的工作流程:
這是我們Handler的大概流程圖,我們在線程中用handler通過sendEmptyMessage方法(或者sendMessage方法)發送消息存到MessageQueue中。而我們剛纔的Looper類,是一個輪詢器,它的作用就是一直從MsgQueue中獲取消息,然後將消息發放到handler中,讓他執行邏輯。
我們還是從looper.prepareMainLooper()開始看吧.
我們發現主類中執行的prepareMainLooper方法其實也是執行prepare方法,我們點進prepare方法。
他在下面執行了一個ThreadLocal.set(new Looper(...))方法,我們暫時可以理解爲我們在ThreadLocal中添加了一個 當前線程的looper對象。
我們繼續看prepareMainLooper,他之後又執行了一個myLooper方法,我們點進去。
這個方法是將我們剛纔存入的當前線程的looper對象取出來。
然後我們來看一下loop方法。
我在裏面寫了很清楚的備註,所以當我們執行了loop方法之後,他就會開始無效循環,一直在尋找當前線程的消息隊列中是否有message,
我們接着看,在下面我們輪詢時候消息隊列有msg時候,我們會讓msg的target對象執行dipatchMessage方法,我們看一看target屬性是什麼:
我們發現他是個Handler類的屬性,其實這個target就是發送msg的那個handler,爲什麼我們下面再說。
我們來接着看一下dispatchMessage方法,
我們發現原來最後會回調到handleMessage方法中,這個方法我們應該很熟悉了,就是我們剛剛執行操作的方法。至於爲什麼target是我們發送msg的handler呢,我們現在來看一下:
我們從handler.sendMessage方法開始看吧:
他從sendMessage一直跳轉了這麼幾個方法,在最後的恩queueMessage方法中,我們看到msg.target= this,將當前的handler設爲msg的target,所以target存儲的就是發送msg的handler。
我們來看一下最後跳轉到消息隊列的enqueueMessage方法:
這個方法其實就是一個鏈表插入,把我們的msg放入到消息隊列中。
所以現在我們知道了,looper的loop方法一旦啓動,就會一直獲取當前線程的looper對象,然後一直輪詢當前對象的消息隊列,當找到消息就發放給msg的handler,讓他執行handleMessage方法,這就是他的工作原理。
下面給大家配上一張邏輯圖和源碼結合的圖: