活用Android的Message Queue(1/3)
转自:http://www.android1.net/
高煥堂的第4本書精美印刷出來囉!!!
PS.========== News ========================
1. 高煥堂的Android培訓課程,請看www.misoo1.com
2. 高煥堂的第4本 Android書籍:<<Android 設計招式之美>>
將於下週上市,請到重慶南路天瓏書店購買。
========== News ========================
<<<本文>>>
1.Message Queue的角色
l在你的Android程式裡,新誕生一個線程,或稱執行緒(Thread)時,並不會自動建立其Message Loop。
lAndroid裡並沒有Global的Message Queue資料結構,例如,不同APK裡的物件不能透過Massage Queue來交換訊息(Message)。
l一個線程可以誕生一個Looper之物件,由它來管理此線程裡的Message Queue。
l你可以誕生Handler之物件來與Looper溝通,以便push新訊息到Message Queue裡;或者接收Looper(從Message Queue取出)所送來的訊息。
l線程A的Handler物件參考可以傳遞給別的線程,讓別的線程B或C等能送訊息來給線程A(存於A的Message Queue裡)。
l線程A的Message Queue裡的訊息,只有線程A所屬的物件可以處理之。
l使用Looper.myLooper可以取得目前線程的Looper物件參考值。
l使用mHandler =newEevntHandler(Looper.myLooper());可誕生用來處理目前線程的Handler物件;其中,EevntHandler是Handler的子類別。
l使用mHandler =newEevntHandler(Looper.getMainLooper());可誕生用來處理main線程的Handler物件;其中,EevntHandler是Handler的子類別。
2.範例之一:Looper物件之角色
Looper類別用來管理特定線程內物件之間的訊息交換(Message Exchange)。你的應用程式可以誕生許多個線程,或稱執行緒(Thread)。而一個線程可以誕生許多個物件,這些物件之間常常需要互相交換訊息。如果有這種需要,您可以替線程誕生一個Looper類別之物件,來擔任訊息交換的管理工作。Looper物件會建立一個MessageQueue資料結構來存放各物件傳來的訊息(包括UI事件或System事件等)。如下圖:
每一個線程(Thread,或稱「執行緒」)裡可含有一個Looper物件以及一個MessageQueue資料結構。在你的應用程式裡,可以定義Handler的子類別來接收Looper所送出的訊息。
//----- Looper_01範例-----
packagecom.misoo.kx04;
importandroid.app.Activity;
importandroid.graphics.Color;
importandroid.os.Bundle;
importandroid.os.Handler;
importandroid.os.Looper;
importandroid.os.Message;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.widget.Button;
importandroid.widget.LinearLayout;
importandroid.widget.TextView;
publicclassac01extendsActivityimplementsOnClickListener {
privatefinalintWC= LinearLayout.LayoutParams.WRAP_CONTENT;
privatefinalintFP= LinearLayout.LayoutParams.FILL_PARENT;
publicTextViewtv;
privateEventHandlermHandler;
privateButtonbtn,btn2,btn3;
publicvoidonCreate(Bundle icicle) {
super.onCreate(icicle);
LinearLayout layout =newLinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
btn=newButton(this);
btn.setId(101);
btn.setBackgroundResource(R.drawable.heart);
btn.setText("test looper");
btn.setOnClickListener(this);
LinearLayout.LayoutParams param =
newLinearLayout.LayoutParams(100,50);
param.topMargin= 10;
layout.addView(btn, param);
btn2=newButton(this);
btn2.setId(102);
btn2.setBackgroundResource(R.drawable.ok_blue);
btn2.setText("exit");
btn2.setOnClickListener(this);
layout.addView(btn2, param);
tv=newTextView(this);
tv.setTextColor(Color.WHITE);
tv.setText("");
LinearLayout.LayoutParams param2 =
newLinearLayout.LayoutParams(FP,WC);
param2.topMargin= 10;
layout.addView(tv, param2);
setContentView(layout);
}
publicvoidonClick(View v) {
switch(v.getId()){
case101:
Looper looper;
looper = Looper.myLooper();
mHandler=newEventHandler(looper);
mHandler.removeMessages(0);
//清除整個MessageQueue裡的事件,確保不會通知到別人
String obj ="This my message!";
Message m =mHandler.obtainMessage(1, 1, 1, obj);
//組裝成一個Message物件
mHandler.sendMessage(m);
//將Message物件送入MessageQueue裡
break;
case102:
finish();
break;
}
}
//------------------------------------------------------
classEventHandlerextendsHandler
{
publicEventHandler(Looper looper) {
super(looper);
}
@Override
publicvoidhandleMessage(Message msg) {
tv.setText((String)msg.obj);
}
}
}
//-------------------------------------------------------
說明:
此程式啟動時,目前線程(即主線程, main thread)已誕生了一個Looper物件,並且有了一個MessageQueue資料結構。
指令:looper = Looper.myLooper();
就呼叫Looper類別的靜態myLooper()函數,以取得目前線程裡的Looper物件之參考值。
指令:mHandler=newEventHandler(looper);
誕生一個EventHandler之物件來與Looper溝通。Activity等物件可以藉由EventHandler物件來將訊息傳給Looper,然後放入MessageQueue裡;EventHandler物件也扮演Listener的角色,可接收Looper物件所送來的訊息。如下圖:
指令:Message m =mHandler.obtainMessage(1, 1, 1, obj);
先誕生一個Message物件,並將資料存入次物件裡。
指令:mHandler.sendMessage(m);
就透過mHandler物件而將訊息m傳給Looper,然後放入MessageQueue裡。
此時,Looper物件看到MessageQueue裡有訊息m,就將它廣播出去,mHandler物件接到此訊息時,會呼叫其handleMessage()函數來處理之,於是輸出"This my message!"於畫面上,如下:
3.範例之二:由別的線程送訊息到主線程的Message Queue
//----- Looper_02範例-----
packagecom.misoo.kx04;
importandroid.app.Activity;
importandroid.graphics.Color;
importandroid.os.Bundle;
importandroid.os.Handler;
importandroid.os.Looper;
importandroid.os.Message;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.widget.Button;
importandroid.widget.LinearLayout;
importandroid.widget.TextView;
publicclassac01extendsActivityimplementsOnClickListener {
privatefinalintWC= LinearLayout.LayoutParams.WRAP_CONTENT;
privatefinalintFP= LinearLayout.LayoutParams.FILL_PARENT;
publicTextViewtv;
privatemyThreadt;
privateButtonbtn,btn2,btn3;
publicvoidonCreate(Bundle icicle) {
super.onCreate(icicle);
LinearLayout layout =newLinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
btn=newButton(this);
btn.setId(101);
btn.setBackgroundResource(R.drawable.heart);
btn.setText("test looper");
btn.setOnClickListener(this);
LinearLayout.LayoutParams param =
newLinearLayout.LayoutParams(100,50);
param.topMargin= 10;
layout.addView(btn, param);
btn2=newButton(this);
btn2.setId(102);
btn2.setBackgroundResource(R.drawable.ok_blue);
btn2.setText("exit");
btn2.setOnClickListener(this);
layout.addView(btn2, param);
tv=newTextView(this);
tv.setTextColor(Color.WHITE);
tv.setText("");
LinearLayout.LayoutParams param2 =
newLinearLayout.LayoutParams(FP,WC);
param2.topMargin= 10;
layout.addView(tv, param2);
setContentView(layout);
}
publicvoidonClick(View v) {
switch(v.getId()){
case101:
t=newmyThread();
t.start();
break;
case102:
finish();
break;
}
}
//------------------------------------------------------
classEHandlerextendsHandler {
publicEHandler(Looper looper) {
super(looper);
}
@Override
publicvoidhandleMessage(Message msg) {
tv.setText((String)msg.obj);
}
}
//------------------------------------------------------
classmyThreadextendsThread{
privateEHandlermHandler;
publicvoidrun() {
Looper myLooper, mainLooper;
myLooper = Looper.myLooper();
mainLooper = Looper.getMainLooper();
String obj;
if(myLooper ==null){
mHandler=newEHandler(mainLooper);
obj ="current thread has no looper!";
}
else{
mHandler=newEHandler(myLooper);
obj ="This is from current thread.";
}
mHandler.removeMessages(0);
Message m =mHandler.obtainMessage(1, 1, 1, obj);
mHandler.sendMessage(m);
}
}
}
//-------------------------------------------------------
Android會自動替主線程建立Message Queue。在這個子線程裡並沒有建立Message Queue。所以,myLooper值為null,而mainLooper則指向主線程裡的Looper物件。於是,執行到指令:
mHandler =newEHandler(mainLooper);此mHandler屬於主線程。
指令:mHandler.sendMessage(m);
就將m訊息存入到主線程的Message Queue裡。mainLooper看到Message Queue裡有訊息,就會處理之,於是由主線程執行到mHandler的handleMessage()函數來處理訊息。此程式輸出畫面為:
4.結語:
lMessage Loop的用途很廣。請你參閱高煥堂所寫的Android系列書籍,尤其是其中的第4本書:<<Android設計招式之美>>。
l以上只是本文的前半段而已,請你繼續閱讀後半段。
---- END ---
更多相关文章
- Android(安卓)NDK简介
- ESC/POS指令集在Android设备上使用实例(通过socket)
- Android(安卓)am 指令的使用
- Android(安卓)am 指令的使用
- Android(安卓)应用程式的基本档案结构
- ANDROID – TOOLBAR STEP BY STEP
- android
- android串口通信——电子扫描枪
- 認識Android的BinderProxy和Binder類別