Android中的handler

鴨脖發表於2012-08-08

這幾天經常在開發android的時候需要用到多執行緒,其實很多地方是必須用到的,比如進度條的更新,動畫的顯示,等等,你必須開一個執行緒來單獨管理這些介面元素的變化,因為你不能因為更新個進度條把主執行緒給阻塞了,這不科學。而且別人都說了,永遠不要阻塞主執行緒,一切從使用者的角度出發。那麼今天我在寫多執行緒的時候,需要更新進度條的progress,那麼就需要在run方法中不斷的屈更新progress這個值,然後再對這個進度條setprogress,怎麼半呢?我的進度條是一個區域性變數,於是我自己定義了一個內部類,把這個進度條物件當作建構函式的引數傳入執行緒類中,然後再在run方法中更新這個progress。然後我直接new了一個物件,然後start了


接下來執行,便丟擲了異常,Only the original thread that created a view hierarchy can touch its views


為什麼呢?

當每個應用程式apk第一次啟動時,Android會同時啟動一個對應的主執行緒(Main Thread)
主執行緒負責處理與UI相關的事件,如:使用者的按鍵事件,使用者接觸螢幕的事件以及螢幕繪圖事件,
並把相關的事件分發到對應的元件進行處理,所以主執行緒通常又被叫做UI執行緒。在android核心剖析這本書中就介紹過這個執行緒類,其實就是ActivityThread這個類。書中這麼講到:

應用程式啟動時,從ActivityThread開始,

ActivityThread從main方法開始執行,呼叫一個方法建立MessageQueue,

然後建立一個ActivityThread物件,在初始化程式碼中會建立一個Handler和一個Binder,binder負責接受呼叫,然後通過handler將呼叫傳送給訊息佇列,

主執行緒會非同步地從訊息佇列中取出訊息並執行相應的動作。


但是在開發Android應用時必須遵守單執行緒模型的原則: 
      Android UI操作並不是執行緒安全的並且這些操作必須在UI執行緒中執行,如果在非UI執行緒中直接操作UI執行緒,
      會丟擲android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that 
      created a view hierarchy can touch its views,這與普通的java程式不同。

由於UI執行緒負責事件的監聽和繪圖,因此,必須保證UI執行緒能夠隨時響應使用者的需求,
UI執行緒裡的操作應該向中斷事件那樣短小,費時的操作(如網路連線)需要另開執行緒,
否則,如果UI執行緒超過5s沒有響應使用者請求,會彈出對話方塊提醒使用者終止應用程式(ANP)


如果在新開的執行緒中需要對UI進行設定,就可能違反單執行緒模型,
因此android採用一種的Message Queue機制保證執行緒間通訊

 Message Queue是一個訊息佇列,用來存放通過Handler傳送的訊息。
Android在第一啟動程式時會預設會為UI thread建立一個關聯的訊息佇列,
可以通過Looper.myQueue()得到當前執行緒的訊息佇列,用來管理程式的一些上層元件,
activities,broadcast receivers 等,你可以在自己的子執行緒中建立Handler與UI thread通訊

Handler會向message queue通過兩種方法傳送訊息:send或post。
這兩種訊息都會插在message queue隊尾並按先進先出執行,
但通過這兩種方法傳送的訊息執行的方式略有不同:
 1)通過send傳送的是一個message物件, 會被handler的 handleMessage()函式處理;
 2)而通過post方法傳送的是一個runnable物件,則會自己執行。


Handler的官方描述:


A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue


.Handler的使用場合:

 

1、 to schedule messages and runnables to be executed as some point in the future;

      安排messages和runnables在將來的某個時間點執行。

2、 to enqueue an action to be performed on a different thread than your own.

      將action入隊以備在一個不同的執行緒中執行。即可以實現執行緒間通訊。比如當你建立子執行緒時,你可以再你的子執行緒中拿到父執行緒中建立的Handler物件,就可以通過該物件向父執行緒的訊息佇列傳送訊息了。由於Android要求在UI執行緒中更新介面,因此,可以通過該方法在其它執行緒中更新介面。


通過Handler更新UI例項:

步驟:

1、建立Handler物件(此處建立於主執行緒中便於更新UI)。

2、構建Runnable物件,在Runnable中更新介面。

3、在子執行緒的run方法中向UI執行緒post,runnable物件來更新UI。


相關文章