1. 程式人生 > >執行緒間通訊的訊息機制的Message和Handler

執行緒間通訊的訊息機制的Message和Handler

Message是訊息機制的資訊載體,開發人員可以在Message物件中封裝資料,封裝資料的方式有:

1)setData(),在Message中封裝Bundle型別的資料,在接收方使用getData()獲取該Bundle物件。

2)arg1屬性,int型別,用於封裝int型別變數

3)arg2屬性,int型別,與arg1相似

4)what屬性,int型別,用於封裝int型別變數,表示訊息的識別符號

5)obj屬性,object型別,用於封裝任意型別的資料

Handler訊息的傳送者和處理者,常用方法有

1)public final boolean sendMessage(Message msg);

2)public void HandleMessage(Message msg);

使用訊息機制傳送處理訊息,

public class MainActivity extends Activity {
private ImageView ivImage;
private Button btnLoadImage;
private Handler handler;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ivImage=(ImageView) findViewById(R.id.imageView1);
                handler=new InnerHandler();

}
/**
* 自定義Handler
* @author Administrator
*/
public class InnerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
//接收訊息
Bitmap bm=(Bitmap) msg.obj;
ivImage.setImageBitmap(bm);
}
}
/**
* 點選按鈕,載入圖片
* @param v
*/
public void doLoadImage(View v){
new Thread(){
public void run() {
//從網路中載入圖片,即耗時操作
Bitmap bm=loadImageFromNetwork();
//建立訊息
Message msg=new Message();
msg.obj=bm;
//傳送訊息
handler.sendMessage(msg);
};
}.start();
}
/**
* 模擬從網路中載入圖片
*/
public Bitmap loadImageFromNetwork(){
Bitmap bm=null;
//模擬網路延遲8秒
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return bm=BitmapFactory.decodeResource(getResources(), R.drawable.meituan);
}


Message存在公有的無參的構造方法,所以可以用new Message()建立Message物件,但是這種做法並不推薦。因為很多時候,需要很頻繁的傳送訊息,很頻繁的建立物件,會導致較大的系統開銷。為了避免較多的Message物件建立和銷燬造成較大的系統開銷,系統使用Message Pool(訊息池)來控制和管理Message物件。

Message Pool的大小為10,即可存放10個Message物件,當需要Message物件時,直接從池中獲取即可,無需建立。獲取Message物件的方法:

1)Message類的obtain靜態方法;

2)Handler的obtainMessage方法;

兩個方法都是過載很多次,我們可以查詢文件,使用方法。

在使用Message時一般遵循以下規則:

1)儘量使用Message的obtain方法或Handler的obtainMessage方法獲取Message物件,而不使用構造方法建立物件。

2)嚴格區分Message物件的arg1,arg2,what屬性。what標識訊息型別,常使用常量表現其意義,而arg1,arg2則表示具體數字意義的資料。

3)可以根據具體情況,將需要封裝的資料設定為全域性變數,在子執行緒中可以直接更新,在主執行緒中直接獲取,而無需封裝。

4)儘量不要在Message中封裝大量的資料,能使用obj屬性封裝的,就不要使用setData()/getData方法,因為其效率更高。

根據以上內容,部分程式碼可以更改為

public class MainActivity extends Activity {
private ImageView ivImage;
private Button btnLoadImage;
private Handler handler;
private Bitmap bm;
        protected static final int LOAD_IMAGE_COMPLETED = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ivImage=(ImageView) findViewById(R.id.imageView1);
handler=new InnerHandler();
}
/**
* 自定義Handler
* @author Administrator
*/
public class InnerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
if(msg.what==LOAD_IMAGE_COMPLETED){
ivImage.setImageBitmap(bm);
}
}
}
/**
* 點選按鈕,載入圖片
* @param v
*/
public void doLoadImage(View v){
new Thread(){
public void run() {
//從網路中載入圖片,即耗時操作
bm=loadImageFromNetwork();
Message msg=new Message();
·msg.what=LOAD_IMAGE_COMPLETED;
handler.sendMessage(msg);
};
}.start();
   }
}


以上程式碼是定義Handler的子類,並重寫handleMessage方法以處理訊息。其實關於Handler處理訊息,我們也可以自定義類實現Handler.Callback介面,並將該介面的實現類物件作為new Handler(Callback callback)的引數以建立Handler物件

以上程式碼部分可以修改為:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ivImage=(ImageView) findViewById(R.id.imageView1);
//handler=new InnerHandler();
handler=new Handler(new InnerCallback());
}
public class InnerCallback implements Handler.Callback{
@Override
public boolean handleMessage(Message msg) {
if(msg.what==LOAD_IMAGE_COMPLETED){
ivImage.setImageBitmap(bm);
}
return false;
}
}