在Android中應用到多線程通信,尤其是新的線程去更新主線程的UI,因爲新線程無法直接更新widget, 所以在Android多應用handler處理多線程的通信。
Handler主要有兩個作用,一是安排消息或者Runnable在某個主線程中某個地方執行,二是安排一個任務去別的線程工作。
提到Handler肯定會設計到Looper,Looper的作用就是替對應的Handler管理消息,每一個Handler都有一個屬於自己的Looper,這是一個對一的關係,在Android中除了主線程外其他線程在使用時不會自動爲handler分配Looper的,所以在新的線程應用Handler的時候必須首選Looper.prepare函數來初始化Looper,然後用loop()函數來做信息循環的處理。
MessageQueue是控制所屬線程的消息,所有的message並不是直接會存儲在MeesageQueue中,通過Looper工作的。MessageQueue, Looper
Handler三者是一對一的關係,並且他們三個和某一個所屬的線程也是一對一的關係,每個線程都有自己的一套Handler機制 。
具體的消息運行機制是Looper將發出的消息放到MessageQueue中,然後循環的傳遞給Handler,Handler會將當前的Message進行處理,然後做出相應的反應。
其實無論怎樣發送,他們的重點只是一條,用的哪個handler發送的消息,就由這個handler處理消息,這個線程所處的線程做出相應的反應。handler和thread是綁定的一對>一關係。 想讓線程接收什麼,就用線程所屬的handler發送消息。
例如子線程給主線程發送消息更新UI 和主線程給子線程發送信息:
public class MainActivity extends Activity implements OnClickListener {
private MyHandler mHandler = null;
private Button btn1;
private TextView mText;
private HanderThread myThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1 = (Button) findViewById(R.id.button1);
mText = (TextView) findViewById(R.id.textview);
btn1.setOnClickListener(this);
mHandler = new MyHandler(Looper.getMainLooper());
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch(v.getId()){
case R.id.button1:
myThread = new HanderThread();
myThread.start();
}
}
class MyHandler extends Handler{
public MyHandler(Looper looper){
super(looper);
}
public void handleMessage(Message msg){
//此函數處理handler發送的消息。
switch(msg.what){
case 4:
String obj = msg.getData().getString("senddata");
mText.setText("receive "+obj);
break;
default:
break;
}
}
}
class HanderThread extends Thread{
HanderThread (){
}
public void run(){
// 在這裏你可以做一些費時的操作,本例只是在這裏發送了一個
//消息給主線程告訴它消息來自子線程,並改變TextView中的文字。
String msg = "from child thread";
Bundle mBundle = new Bundle();
Message Msg = mHandler.obtainMessage();
mBundle.putString("senddata",msg);
Msg.what = 4;
Msg.setData(mBundle);
//要記住這裏發送這個message的是mHandler,這個handler是
//屬於主線程的handler所以主線程來處理這個消息。並且有主線程
//來做出相應的改變。
mHandler.sendMessage(Msg);
}
}
public class MainActivity extends Activity {
private Handler mMainHandler = null;
private TextView info = null;
private Button msgBtn = null;
ChildThread child1 = null;
class ChildThread extends Thread {
private Handler childHander = null;
private String CHILD_TAG = "ChildThread";
public void run() {
this.setName("ChildThread");
// 初始化消息循環隊列,需要在Handler創建之前
//必須用這個函數和loop(),否則報錯。
Looper.prepare();
childHander = new Handler() {
@Override
public void handleMessage(Message msg) {
// 在子線程中可以做一些耗時的工作
String sMsg = "";
Message toMain = new Message();
// mMainHandler.obtainMessage();
toMain.obj = "This message from "
+ this.getLooper().getThread().getName()
+ " the main thread had sent " + (String) msg.obj;
// 這個消息是主線程的handler發送的,由主線程處理,這裏
//主要是改變主線程TextView的文字。
mMainHandler.sendMessage(toMain);
}
};
//使消息開始循環。
Looper.loop();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
info = (TextView) findViewById(R.id.info);
msgBtn = (Button) findViewById(R.id.bt1);
mMainHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 處理收到的消息。
info.setText((String) msg.obj);
}
};
child1 = new ChildThread();
child1.start();
msgBtn.setOnClickListener(new View.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()
+ " say hello";
// 因爲發送這個小時的handler是子線程的所有子線程處理。
// 哪個線程處理消息要看是由屬於哪個線程的handler發出的消息。
child1.childHander.sendMessage(msg);
}
}
});
}
}