轉自:AndroidChina » Handler有何作用?如何使用?
一 Handler作用和概念
- 運行在某個線程上,共享線程的消息隊列;
- 接收消息、調度消息,派發消息和處理消息;
- 實現消息的異步處理;
Handler能夠讓你發送和處理消息,以及Runnable對象;每個Handler對象對應一個Thread和Thread的消息隊列。當你創建一個Handler時,它就和Thread的消息隊列綁定在一起,然後就可以傳遞消息和runnable對象到消息隊列中,執行消息後就從消息隊列中退出。
Handler的作用就是:調度消息和runnable對象去被執行;使動作在不同的線程中被執行。
當一個應用程序中進程被創建時,它的主線程專門運行消息隊列(messageQueue),去管理頂層的應用程序相關的對象如:activity,broadcastReceiver,windows等,你可以創建你的Thread,和主線程進行交互——通過Handler,交互的方法就是通過post或者sendMessage。但是在你的新線程中,給定的Message或者Runnable,會在適當的時候的被調度和處理。
(即不會被立即處理——阻塞式)。
實際上就是建立消息處理模型/系統
要學習Handler,看到肯定是和消息有關,可能還是需要先熟悉一下消息系統的構成和簡單原理。
下面就先學習一下消息系統的基本原理。
二 消息系統的基本原理和構成從一般的消息系統模型的建立大致構成以下幾個部分:
- 消息原型
- 消息隊列
- 發送消息
- 消息循環
- 消息獲取
- 消息派發
- 消息處理
大致模型圖如下:
消息系統模型一般會包括以上七個部分(消息原型,消息隊列,消息發送,消息循環,消息獲取,消息派發,消息處理)。實際上的核心是消息隊列和消息循環,其餘部分都是圍繞這兩部分進行的。
從前面文檔的分析中我們知道Handler就是用來建立消息處理的系統模型,那麼和這裏基本消息系統模型相比,那麼Handler又是如何囊括這七個部分的呢?
在Android中對這六個部分進行了抽象成四個獨立的部分(消息循環):
Handler,Message,MessageQueue,Looper;
- Message就是消息原型,包含消息描述和數據,
- MessageQueue就是消息隊列,
- Looper完成消息循環 ,
- Handler就是駕馭整個消息系統模型,統領Message,MessgeQueue和Looper;
Handler能夠實現消息系統模型,那麼具體是如何進行工作的呢,下面探究一下這其中工作的方法和原理。
三 Handler工作原理分析要了解Handler工作原理,先看一下這個系統模型具體組成的層次結構框架是個什麼樣的。
1,Looper:
實現Thread的消息循環和消息派發,缺省情況下Thread是沒有這個消息循環的,即沒有Looper;
需要主動去創建,然後啓動Looper的消息循環loop;與外部的交互通過Handler進行;
2,MessageQueue:
消息隊列,由Looper所持有,但是消息的添加是通過Handler進行;
消息循環和消息隊列都是屬於Thread,而Handler本身並不具有Looper和MessageQueue;
但是消息系統的建立和交互,是Thread將Looper和MessageQueue交給某個Handler維護建立消息系統模型。所以消息系統模型的核心就是Looper。消息循環和消息隊列都是由Looper建立的,而建立Handler的關鍵就是這個Looper。
一個Thread同時可以對應多個Handler,一個Handler同時只能屬於一個Thread。Handler屬於哪個Thread取決於Handler在那個Thread中建立。
在一個Thread中Looper也是唯一的,一個Thread對應一個Looper,建立Handler的Looper來自哪個Thread,Handler屬於哪個Thread。
故建立Thread消息系統,就是將Thread的Looper交給Handler去打理,實現消息系統模型,完成消息的異步處理。
Handler與Thread及Looper的關係可以用下面圖來表示:
Handler並不等於Thread,必須通過Thread的Looper及其MessageQueue,用來實現Thread消息系統模型,依附於Thread上。
在線程建立Handler時:
使Handler滿足消息系統需要的條件,將Thread中的Looper和MessageQueue交給Handler來負責維護。
在線程中建立Handler,需要做以下工作:
- 獲取Thread中的Looper交給Handler的成員變量引用維護;
- 通過Looper獲取MessageQueue交給Handler的成員變量引用維護。
那麼消息系統模型建立完成之後,按照消息系統運行,從Handler來看就是發送消息派發消息,與此線程消息系統的交互都由Handler完成。
消息發送和派發接口:
- post(runnable)消息,Runnable是消息回調,經過消息循環引發消息回調函數執行;
- sendMessage(Message)消息,經過消息循環派發消息處理函數中處理消息;
- dispatchMessage派發消息,若是post或帶有回調函數則執行回調函數,否則執行消息處理函數Handler的handleMessage(通常派生類重寫)。
以上就是Handler如何實現Thread消息系統模型的大致介紹。下面將具體分析是如何實現消息系統模型運行的。
四 Handler實現流程分析我們知道Handler就是一個消息系統的外殼,屬於某個Thread幷包裝了Thread的Looper及其MessageQueue;與外部進行交互(同一個線程內或者線程之間),接收派發和處理消息,消息系統模型的核心是Looper。
下面看看Handler是如何建立跑起來的,以msg消息爲例,runnable實質是一樣。
1,Handler的建立
Handler唯一屬於某個Thread,在某個Thread中建立Handler時,需要獲取Thread的Looper及其MessageQueue,建立Handler關鍵是Looper的來源。
Handler提供了好幾個構造函數但其本質一致:由外部傳入Looper:當前線程或其他線程
從當前線程獲取:由創建Handler的Thread決定
不管哪種方式,我們知道Thread在默認情況下是沒有建立消息循環Looper實例的。要實現消息循環必須確保Thread的Looper建立。如何確保呢?
Looper提供了靜態函數:
看到這裏剛開始讓我很是奇怪和迷惑:
Looper一個獨立的類,又不屬於某個Thread,而這裏創建Looper的函數又是靜態的,屬於整個Looper類;創建Looper之後交給靜態成員變量sThreadLocal保存,獲取sThreadLocal.get(),那麼一個靜態變量屬於整個類,屬性更改始終有效。一次創建之後
sThreadLocal.get()永遠都不等於null!
而Thread和Looper是唯一對應的,那這裏豈不是所有的Thread都是用同一個Looper,不可能!所以肯定這個ThreadLocal是有玄機的。網上一查:
ThreadLocal:
維護線程的變量,爲每個使用該變量的線程實例提供獨立的變量副本,每個線程都能夠獨立使用該變量,而互不影響。(詳細可參考:http://blog.csdn.net/qjyong/article/details/2158097)
所以每一個線程調用Looper.prepare時,都會創建爲其唯一的Looper。要建立Handler,需要先創建線程的Looper,才能建立消息系統模型。通過Looper我們建立了Thread上的消息系統模型Handler,可以來進行消息系統的一系列流程了。
2,消息發送
消息發送兩種方式:post和sendMessage;
- post:針對runnable對象;Runnable是一個接口,就是一個回調函數(提供了run方法)
- sendMessage:針對Message對象;
下面通過代碼具體看一下這個過程:
看到post和sendMessage發送消息時,僅僅是對象不同而已,Runnable和Message;但實際上都是Message的形式來描述。
這跟我通常理解的消息機制不同:
通常post消息是將消息加入到消息隊列中並不立即執行就返回,send消息是立即執行等待消息執行完才返回。而這裏post或者send都是將消息放入到消息隊列中,然後立即返回,等待消息循環時獲取消息被執行。
這裏提供了衆多的消息發送方法來指定消息的執行時間和順序,具體可以查看源代碼。
消息執行順序是根據消息隊列中消息的排列順序而定。下面看一下發送消息後將消息加入到消息隊列中的代碼:
由Handler調用MessageQueue的enqueueMessage方法:
可以看到是按照時間順序將消息加入到MessageQueue中;
現在將消息加入到消息隊列中存儲起來,消息並未得到處理,下一步必然是如何派發消息和處理消息。
3,消息派發
建立Thread消息循環由Looper完成,存在一個消息調度死循環:
這裏看到消息派發是由Message的target完成,這個target是什麼呢?是一個Handler。消息系統是通過Handler用來與外部交互,把消息派發出去。可以看到沒有這個Handler,消息循環將結束。
消息派發由Looper通過Handler完成:
通過消息派發,這樣就實現消息的異步處理。
4,消息原型
前面看到消息發送有兩種方式:
post(Runnable對象),sendMessage(Message對象),而中間都是通過Message對象
保存在MessageQueue中。然後消息派發時處理方式不同。如果在sendMessage時將將消息對象附上Runnable對象,則post和sendMessage沒有區別了。所以這兩種方式很好理解基本一致,處理的方式不同罷了。
消息系統模型中,我們的真正的消息原型是什麼,都具有那些功能,下面看一下Message中到底包含了那些東西,能有效幫助我們合理的運用消息系統來完成一些任務和處理。
Message消息原型:
看到提供了很豐富的屬性來描述消息,針對具體問題選擇使用那些屬性去怎麼樣描述消息了。獲取新的Message對象時,Message提供了obtain方法:避免我們自己去分配Message新的對象,通過obtain獲取,可能從MessagePool中獲取,節約開銷。
下面看一下這個MessagePool是如何建立的:
通常消息處理完畢的時候,消息也基本上處於無用狀態可以釋放回收了。對於需要頻繁的創建釋放的對象來說,創建和釋放類實例都是要開銷的,太頻繁的使開銷增大不好,像Message這種很有可能會頻繁的創建。於是我們可以將創建的對象用完之後保存在一個Pool裏面,以便再重複利用節約頻繁創建釋放開銷。是如何建立的呢?必然是在消息處理完畢之後才能進行。
MessagePool建立:
以上這就是整個Handler作用及消息系統模型的建立。
使用也非常簡單,雖然有很多方式,但只要理解Handler是建立在Looper上,實現Thread的消息系統處理模型,實現消息異步處理,我想對與Handler基本應用上沒有什麼不能理解的了。其他方面可以去看源碼了。
Handler使用起來是非常簡單的,關鍵就是如何利用消息的異步處理,來合理的完成我們需要功能和任務。對於一個Thread,我們使用好幾個Handler來進行異步處理,也可以創建新的Thread,通過Handler來實現消息異步處理等等,應用場景很多如何用的好用的合理,這就沒什麼經驗了。