練習(xí)心得
整個(gè)實(shí)現(xiàn)涉及Looper、Handler、MessageQueue分飞、Message 4個(gè)類
- Looper:一個(gè)線程只能有一個(gè)Looper實(shí)例千康,通過Looper.prepare()獲取實(shí)例崭篡,構(gòu)造實(shí)例過程同時(shí)生成MessageQueue
- Handler:負(fù)責(zé)發(fā)送消息和處理消息(即負(fù)責(zé)收發(fā))
- MessageQueue:一個(gè)線程僅能有一個(gè),以隊(duì)列先進(jìn)先出的方式存儲(chǔ)Handler發(fā)送的消息
- Looper.loop()方法以死循環(huán)的方式不斷從MessageQueue拿取Message交給Handler處理吧秕,一定要放到最后一條語句琉闪,因?yàn)槭撬姥h(huán)獲取隊(duì)列中的消息,會(huì)阻塞同一線程的其它語句執(zhí)行砸彬〉弑校可以通過調(diào)用Looper.quit()終止死循環(huán)
- Message:消息載體,注意每次handler投遞的message都要是一個(gè)新的實(shí)例砂碉,否則報(bào)IllegalStateException,This message is already in use
代碼樣例
/**
* Created by Rambo
*/
public class MyActivity extends MainActivity {
private EditText myEditText = null;
private Button stop = null;
private HashMap<String, String> asynTaskParams = new HashMap<>();
private Handler mainThreadHandler = null;
private Handler otherThreadHandler = null;
private final int UPDATE_EDITTEXT = 0x01;
private final int UPDATE_BUTTONTEXT = 0x02;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
myEditText = (EditText) findViewById(R.id.myEditText);
stop = (Button) findViewById(R.id.stop);
// 主線程定義handler用于處理其它線程發(fā)送過來的消息
mainThreadHandler = new Handler() {
/**
* 消息處理回調(diào)
* @param msg 消息信息
*/
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {// 通過msg.what區(qū)分消息來源
case UPDATE_EDITTEXT:
Log.v(TAG, "otherThread call MainThread handler running:" + Thread.currentThread().getName());
myEditText.setText(msg.getData().get("threadIndex").toString());
break;
case UPDATE_BUTTONTEXT:
Log.v(TAG, "timer call MainThread handler running:" + Thread.currentThread().getName());
stop.setText("stop" + msg.getData().get("timerIndex").toString());
break;
}
}
};
// 定義新線程蛀蜜,執(zhí)行耗時(shí)任務(wù)
Thread otherThread = new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare(); // 創(chuàng)建非主線程的Looper,同時(shí)在Looper的構(gòu)造方法中創(chuàng)建MessageQueue(先進(jìn)先出隊(duì)列),一個(gè)線程中只能有一個(gè)Looper和MessageQueue
// 非主線程處理器,其它線程可通過handler與該線程進(jìn)行數(shù)據(jù)通訊增蹭,這也是線程間通訊的一種機(jī)制
otherThreadHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
default:
Log.v(TAG, "otherThread-otherThreadHandler.handleMessage");
}
}
};
Log.v(TAG, "otherThread running:" + Thread.currentThread().getName());
try {
for (int index = 0; index < 5; index++) {
// 定義要發(fā)給主線程handler的消息,每次handler投遞的message都要是一個(gè)新的實(shí)例滴某,否則報(bào)IllegalStateException,This message is already in use
Message otherThreadMsg = new Message();
otherThreadMsg.what = UPDATE_EDITTEXT;
Bundle data = new Bundle();
data.putInt("threadIndex", index);
Thread.sleep(1000);
otherThreadMsg.setData(data);
// 通過主線程handler實(shí)例發(fā)送消息,相當(dāng)于自發(fā)自收
mainThreadHandler.sendMessage(otherThreadMsg);
}
} catch (Exception e) {
e.printStackTrace();
}
// 該語句觸發(fā)Looper不斷從MessageQueue中獲取新消息交由handler處理滋迈,
// 一定要放到最后一條語句霎奢,因?yàn)槭撬姥h(huán)獲取隊(duì)列中的消息,會(huì)阻塞同一線程的其它語句執(zhí)行
Looper.loop();
}
});
otherThread.start();
// 定時(shí)任務(wù)饼灿,會(huì)起新的線程執(zhí)行run代碼塊
new Timer().schedule(new TimerTask() {
@Override
public void run() {
Log.v(TAG, "TimerThread running:" + Thread.currentThread().getName());
try {
for (int index = 0; index < 5; index++) {
// 注意每次handler投遞的message都要是一個(gè)新的實(shí)例幕侠,否則報(bào)IllegalStateException,This message is already in use
Message timerThreadMsg = new Message();
timerThreadMsg.what = UPDATE_BUTTONTEXT;
Bundle data = new Bundle();
data.putInt("timerIndex", index);
Thread.sleep(1000);
timerThreadMsg.setData(data);
mainThreadHandler.sendMessage(timerThreadMsg);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, 0);// 表示不延遲
while (otherThreadHandler == null){
}
otherThreadHandler.sendEmptyMessage(0);
}
運(yùn)行日志如下:
日志