Andriod提供了 Handler 和 Looper 來滿足線程間的通信。例如一個子線程從網絡上下載了一副圖片,當它下載完成後會發送消息給主線程,這個消息是通過綁定在主線程的Handler來傳遞的。
在Android,這裡的線程分為有消息循環的線程和沒有消息循環的線程,有消息循環的線程一般都會有一個Looper,這個事android的新 概念。我們的主線程(UI線程)就是一個消息循環的線程。針對這種消息循環的機制,我們引入一個新的機制Handle,我們有消息循環,就要往消息循環裡 面發送相應的消息,自定義消息一般都會有自己對應的處理,消息的發送和清除,消息的的處理,把這些都封裝在Handle裡面,注意Handle只是針對那 些有Looper的線程,不管是UI線程還是子線程,只要你有Looper,我就可以往你的消息隊列裡面添加東西,並做相應的處理。 但是這裡還有一點,就是只要是關於UI相關的東西,就不能放在子線程中,因為子線程是不能操作UI的,只能進行數據、系統等其他非UI的操作。
但是這裡還有一點,就是只要是關於UI相關的東西,就不能放在子線程中,因為子線程是不能操作UI的,只能進行數據、系統等其他非UI的操作。
一個Handler的創建它就會被綁定到這個線程的消息隊列中,如果是在主線程創建的,那就不需要寫代碼來創建消息隊列了,默認的消息隊列會在主線程被創建。但是如果是在子線程的話,就必須在創建Handler之前先初始化線程的消息隊列。如下面的代碼:
Java代碼
class ChildThread extends Thread {
public void run() {
/*
* 創建 handler前先初始化Looper.
*/
Looper.prepare();
/*
* 在子線程創建handler,所以會綁定到子線程的消息隊列中
*
*/
mChildHandler = new Handler() {
public void handleMessage(Message msg) {
/*
* Do some expensive operations there.
*/
}
};
/*
* 啟動該線程的消息隊列
*/
Looper.loop();
}
}
當Handler收到消息後,就會運行handleMessage(…)的回調函數,可以在裡面做一些耗時的操作。
最後完成了操作要結束子線程時,記得調用quit()來結束消息循環隊列。
mChildHandler.getLooper().quit();
下面是一個線程間通信的小例子:
public class omg extends Activity
{
private static final String TAG = "MainThread";
private Handler mMainHandler = null;
private TextView info = null;
private Button msgBtn = null;
private Button btn1 = null;
private int nClick = 0;
ChildThread child1 = null;
ChildThread child2 = null;
class ChildThread extends Thread {
private Handler childHander = null;
private int nClickTimes = 0;
private static final String CHILD_TAG = "ChildThread";
public void run() {
this.setName("ChildThread");
// 初始化消息循環隊列,需要在Handler創建之前
Looper.prepare();
childHander = new Handler() {
@Override
public void handleMessage(Message msg) {
Log.i(CHILD_TAG,
"Got an incoming message from the main thread - "
+ (String) msg.obj);
try {
// 在子線程中可以做一些耗時的工作
String sMsg = "";
sleep(1000);
Message toMain = new Message();
// mMainHandler.obtainMessage();
sMsg = String.valueOf(++nClickTimes);
toMain.obj = sMsg + "This is "
+ this.getLooper().getThread().getName()
+ ". 你發送了消息: \"" + (String) msg.obj + "\"?"
+ "這是弟" + sMsg + "次 ";
mMainHandler.sendMessage(toMain);
Message toChild = new Message();
toChild.obj = "over";
// mChildHandler.sendMessage(toChild);
Log.i(CHILD_TAG, "Send a message to the main thread - "
+ (String) toMain.obj);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
// 啟動子線程消息循環隊列
Looper.loop();
}
}
// //////////////////////////////////////////////////////////////////////////
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
info = (TextView) findViewById(R.id.info);
msgBtn = (Button) findViewById(R.id.msgBtn);
btn1 = (Button) findViewById(R.id.button1);
mMainHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Log.i(TAG, "Got an incoming message from the child thread - "
+ (String) msg.obj);
// 接收子線程的消息
info.setText((String) msg.obj + String.valueOf(nClick));
}
};
child1 = new ChildThread();
child1.start();
child2 = new ChildThread();
child2.start();
msgBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (child1.childHander != null) {
// 發送消息給子線程
Message childMsg = child1.childHander.obtainMessage();
Message msg = new Message();
msg.obj = mMainHandler.getLooper().getThread().getName()
+ " says Hello and msbBtn sending";
child1.childHander.sendMessage(msg);
Log.i(TAG, "Send a message to the child thread - "
+ (String) msg.obj);
}
}
});
btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (child2.childHander != null) {
// 發送消息給子線程
Message childMsg = child2.childHander.obtainMessage();
Message msg = new Message();
msg.obj = mMainHandler.getLooper().getThread().getName()
+ " says Hello and btn1 sending";
child2.childHander.sendMessage(msg);
Log.i(TAG, "Send a message to the child thread - "
+ (String) msg.obj);
}
}
});
}
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "Stop looping the child thread's message queue");
if (child1.childHander != null) {
child1.childHander.getLooper().quit();
}
if (child2.childHander != null) {
child2.childHander.getLooper().quit();
}
}
}