出於性能優化考慮,Android的UI操做並非線程安全的,這意味着若是有多個線程併發操做UI組件,可能致使線程安全問題。爲了解決這個問題,Android制定了一條簡單的規則:只容許UI線程修改Activity裏的UI組件。程序員
當一個程序第一次啓動時,Android會同時啓動一條主線程(Main Thread),主線程主要負責處理與UI相關的事件,如用戶的按鍵事件、用戶接觸屏幕的事件及屏幕繪圖事件,並把相關的事件分發到對應的組件進行處理。因此主線程一般又被叫作UI線程。安全
Android的消息傳遞機制是另外一種形式的「事件處理」,這種機制主要是爲了解決Android應用的多線程問題——Android平臺只容許UI線程修改Activity裏的UI組件,這樣就會致使新啓動的線程沒法動態改變界面組件的屬性值。但在實際Android應用開發中,尤爲是涉及動畫的遊戲開發中,須要讓新啓動的線程週期性地改變界面組件的屬性值,這就須要藉助於Handler的消息傳遞機制來實現了。性能優化
Handler類的主要做用有兩個:多線程
一、在新啓動的線程中發送消息。併發
二、在主線程中獲取、處理消息。oop
爲了讓主線程能「適時」地處理新啓動的線程所發送的消息,顯然只能經過回調的方式來實現——開發者只要重寫 Handler 類中處理消息的方法,當新啓動的線程發送消息時,消息會發送到與之關聯的 MessageQueue ,而 Handler 會不斷地從MessageQueue 中獲取並處理消息——這將致使 Handler 類中處理消息的方法被回調。性能
Handler類包含以下方法用於發送、處理消息。優化
一、void handleMessage(Message msg):處理消息的方法。該方法一般用於被重寫。動畫
二、final boolean hasMessages(int what):檢查消息隊列中是否包含what屬性爲指定值得消息。spa
三、final boolean hsaMessages(int what,Object object):檢查消息隊列中是否包含what屬性爲指定值且object屬性爲指定對象的消息。
四、多個重載的 Message obtainMessage():獲取消息。
五、sendEmptyMessage(int what):發送空消息。
六、final boolean sendEmptyMessageDelayed(int what,long delayMills):指定多少毫秒以後發送空消息。
七、final boolean sendMessage(Message msg):當即發送消息。
八、final boolean sendMessageDelayed(Message msg,long delayMillis):指定多少毫秒以後發送消息。
藉助於上面這些方法,程序能夠方便地利用Handler 類進行消息傳遞。
爲了更好的理解Handler的工做原理,先介紹一下與Handler一塊兒工做的幾個組件。
一、Message:Handler 接受和處理的消息對象
二、Looper:每一個線程只能擁有一個Looper。它的loop方法負責讀取MessageQueue中的消息,讀到消息以後就把消息交給發送消息的Handler進行處理。
三、MessageQueue:消息隊列,它採用先進先出的方法來管理Message。程序建立Looper對象時會在它的構造器中建立Looper對象。Looper 提供的構造器源代碼以下:
1 private Looper() 2 { 3 mQueue=new MessageQueue(); 4 mRun=true; 5 mThread=Thread.currentThread(); 6 }
該構造器使用了 private 修飾,代表程序員沒法經過構造器建立Looper對象。從上面的代碼中不難看出,程序在初始化Looper時會建立一個與之關聯的 MessageQueue ,這個MessageQueue就負責管理消息。
一、Handler:它的做用有兩個——發送消息和處理消息,程序使用Handler發送消息,被Handler發送的消息必須被送到指定的MessageQueue。也就是說,若是但願Handler正常工做,必須在當前線程中有一個MessageQueue,不然消息就沒有MessageQueue進行保存了。不過MessageQueue是由Looper負責管理的,也就是說,若是但願Handler正常工做,必須在當前線程中有一個Looper對象,爲了保證當前線程中有Looper對象,能夠分以下兩種狀況處理。
一、主UI線程中,系統已經初始化了一個Looper對象,所以程序直接建立Handler便可,而後就可經過Handler來發送消息、處理消息。
二、程序員本身啓動的子線程,程序員必須本身建立一個Looper對象,並啓動它。建立Looper對象調用它的prepare()方法便可。
prepare()方法保證每一個線程最多隻有一個Looper對象。prepare()方法的源代碼以下:
public static final void prepare() { if(sThreadLocal.get()!=null) { throw new RuntimeException("Only one Looper may be createed per thread"); } sThreadLocal.set(new Looper()); }
而後調用Looper 的靜態 loop() 方法來啓動它。loop()方法使用一個死循環不斷取出MessageQueue 中的消息,並將取出的消息分給對應的Handler進行處理。
概括起來,Looper、MessageQueue、Handler 各自的做用以下:
一、Looper:每一個線程只有一個Looper,它負責管理 MessageQueue ,會不斷地從MessageQueue中取出消息。並將消息分給對應的Handler處理。
二、MessageQueue:由Looper負責管理。它採用先進先出的方法來管理Message。
三、Handler:它能把消息發送給Looper管理的MessageQueue,並負責處理Looper分給它的消息。
在線程中使用Handler的步驟以下:
一、調用Looper的prepare()方法爲當前線程建立Looper對象,建立Looper對象時,它的構造器會建立與之配套的MessageQueue。
二、有了Looper以後,建立Handler子類的實例,重寫handlerMessage()方法,該方法負責處理來自於其餘線程的消息。
三、調用Looper的loop()方法啓動Looper。