1. 程式人生 > >眼睛一閉一睜一天就過去了哼,眼睛一閉不睜一輩子就過去了哼。

眼睛一閉一睜一天就過去了哼,眼睛一閉不睜一輩子就過去了哼。

Android執行緒間通訊機制

當android應用程式執行時,一個主執行緒被建立(也稱作UI執行緒),此執行緒主要負責處理UI相關的事件,由於Android採用UI單執行緒模型,所以只能在主執行緒中對UI元素進行操作,如果在非UI執行緒直接對UI進行了操作,則會報錯,另外,對於運算量較大的操作和IO操作,我們需要新開執行緒來處理這些工作,以免阻塞UI執行緒,子執行緒與主執行緒之間是怎樣進行通訊的呢?此時就要採用訊息迴圈機制(Looper)與Handler進行處理。

一、基本概念

Looper:每一個執行緒都可以產生一個Looper,用來管理執行緒的Message,Looper物件會建立一個MessgaeQueue資料結構來存放message。

Handler:與Looper溝通的物件,可以push訊息或者runnable物件到MessgaeQueue,也可以從MessageQueue得到訊息。

檢視其建構函式:

Default constructor associates this handler with the queue for the current thread.//如不指定Looper引數則預設利用當前執行緒的Looper建立

Use the provided queue instead of the default one.//使用指定的Looper物件建立Handler

執行緒A的Handler物件引用可以傳遞給別的執行緒,讓別的執行緒B或C等能送訊息來給執行緒A。

執行緒A的Message Queue裡的訊息,只有執行緒A所屬的物件可以處理。

注意:Android裡沒有global的MessageQueue,不同程序(或APK之間)不能通過MessageQueue交換訊息。

二、Handler通過Message通訊的基本方式

使用Looper.myLooper可以取得當前執行緒的Looper物件。

使用mHandler = new Handler(Looper.myLooper()); 可產生用來處理當前執行緒的Handler物件。

使用mHandler = new Handler(Looper.getMainLooper()

); 可誕生用來處理main執行緒的Handler物件。

使用Handler傳遞訊息物件時將訊息封裝到一個Message物件中,Message物件中主要欄位如下:

public int

arg1

當需要傳遞的訊息是整形時arg1 和 arg2 是一種低成本的可選方案,他使用 setData()/getData()訪問或修改欄位。 

public int

arg2

同上

obj

可傳送的任意object型別.

public int

what

Int型別使用者自定義的訊息型別碼

Message物件可以通過Message類的建構函式獲得,但Google推薦使用Message.obtain()方法獲得,該方法會從全域性的物件池裡返回一個可複用的Messgae例項,API中解釋如下:

Constructor (but the preferred way to get a Message is to call).

Handler發出訊息時,既可以指定訊息被接受後馬上處理,也可以指定經過一定時間間隔之後被處理,如(Message msg, long delayMillis),具體請參考API。

注意:在Android裡,新誕生一個執行緒,並不會自動建立其Message Loop

可以通過呼叫Looper.prepare()為該執行緒建立一個MessageQueue,再呼叫Looper.loop()進行訊息迴圈

下面舉例說明:

在main.xml中定義兩個button及一個textview

複製程式碼
<Button

android:id="@+id/a"

android:layout_width
="80dp"

android:layout_height
="60dp"

android:padding
="6dp"

android:layout_marginTop
="10dp"

android:text
="Test looper"

android:hint
="Test looper" />

<Button

android:id="@+id/b"

android:layout_width
="80dp"

android:layout_height
="60dp"

android:padding
="6dp"

android:layout_marginTop
="10dp"

android:text
="Exit" />

<TextView

android:id="@+id/tv"

android:layout_width
="fill_parent"

android:layout_height
="wrap_content"

android:layout_marginTop
="10dp"/>
複製程式碼

Activity原始碼如下:

複製程式碼
  1 public class HandlerTestActivity extends Activity implements Button.OnClickListener{
2
3 public TextView tv;
4
5 private myThread myT;
6
7 Button bt1, bt2;
8
9 /** Called when the activity is first created. */
10
11 @Override
12
13 public void onCreate(Bundle savedInstanceState) {
14
15 super.onCreate(savedInstanceState);
16
17 setContentView(R.layout.main);
18
19 bt1 = (Button)findViewById(R.id.a);
20
21 bt2 = (Button)findViewById(R.id.b);
22
23 tv = (TextView)findViewById(R.id.tv);
24
25 bt1.setId(1);//為兩個button設定ID,此ID用於後面判斷是哪個button被按下 26
27 bt2.setId(2);
28
29 bt1.setOnClickListener(this);//增加監聽器 30
31 bt2.setOnClickListener(this);
32
33 }
34
35
36
37 @Override
38
39 public void onClick(View v) {
40
41 // TODO Auto-generated method stub 42
43 switch(v.getId()){//按鍵事件響應,如果是第一個按鍵將啟動一個新執行緒 44
45 case 1:
46