活用Android的Message Queue(2)
1.复习Message Queue的角色
在上一篇里,介绍了Android的Thread、Looper、Message Queue和Handler四者间之关系。
先复习如下:
lUI thread通常就是main thread,而Android启动程序时(即创建Process时)会替它建立一个Message Queue。
l当然需要一个Looper对象,来管理该Message Queue。
l我们可以创建Handler对象来push新消息到Message Queue里;或者接收Looper(从Message Queue取出)所送来的消息。
l线程A的Handler对象引用可以传递给别的线程,让别的线程B或C等能发送消息来给线程A(存于A的Message Queue里)。
l线程A的Message Queue里的消息,只有线程A所属的对象可以处理之。
了解了四者间之关系后,在本篇里,就能来思考如何让主线程与子线程之间互相沟通了。包括,子线程push消息到主线程的Message Queue里,并触发主线程去执行某项工作(即执行某个函数)。
2.由别的线程发送消息到主线程的Message Queue(续)
在上一篇文章里,使用如下程序片段:
//classac01extendsActivity {
// ………
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);
}
}
}
这个mHandler定义于myThread类别里,而且由子线程执行指令:mHandler=newEHandler(mainLooper);
来创建EHandler对象;但是这个mHandler确是属于main线程的(用来存取主线程的MessageQueue),所以指令:
mHandler.sendMessage(m);是将m丢到主线程的MessageQueue里。
此外,我们也可以将mHandler定义于ac01类别里。如下程序范例:
//----- Looper_03范例-----
publicclassac01extendsActivityimplementsOnClickListener {
privatefinalintWC= LinearLayout.LayoutParams.WRAP_CONTENT;
privatefinalintFP= LinearLayout.LayoutParams.FILL_PARENT;
publicTextViewtv;
privatemyThreadt;
privateButtonbtn,btn2;
EventHandlerh;
Contextctx;
publicvoidonCreate(Bundle icicle) {
super.onCreate(icicle);
ctx=this;
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:
h=newEventHandler(Looper.myLooper());
t=newmyThread();
t.start();
break;
case102:
finish();
break;
}
}
//------------------------------------------------
publicclassEventHandlerextendsHandler {
publicEventHandler(Looper looper) {
super(looper);
}
@Override
publicvoidhandleMessage(Message msg) {
((Activity)ctx).setTitle((String)msg.obj);
}
}
//------------------------------------------------------
classmyThreadextendsThread{
publicvoidrun() {
String obj ="from myThread";
Message m =h.obtainMessage(1, 1, 1, obj);
h.sendMessage(m);
}
}
}
//------------------------------------------------------
指令:h=newEventHandler(Looper.myLooper());
此h是属于main线程的(用来存取主线程的MessageQueue)。在myThread类别里的指令:h.sendMessage(m);
虽然是由子线程执行该指令,还是将m丢到主线程的MessageQueue里。于是,子线程所执行的run()函数,就顺利将m丢给主线程(的Message Queue),并触发了主线程去执行handleMessage()函数了。显示出画面如下:
图1
上述的指令:
myLooper = Looper.myLooper();
mainLooper = Looper.getMainLooper();
………
mHandler=newEHandler(mainLooper);
………
mHandler=newEHandler(myLooper);
………
都明显地指明mHandler是负责存取哪一个线程的Message Queue。不过,有时候并不需要特别指明。例如上述的onClick()函数和EventHandler类别,可改写为:
//----- Looper_03aa范例-----
//classac01extendsActivity {
// ………
publicvoidonClick(View v) {
switch(v.getId()){
case101:
h=newEventHandler();
t=newmyThread();
t.start();
break;
case102:
finish();
break;
}
}
//------------------------------------------------
publicclassEventHandlerextendsHandler {
@Override
publicvoidhandleMessage(Message msg) {
((Activity)ctx).setTitle((String)msg.obj);
}
}
//------------------------------------------------------
classmyThreadextendsThread{
publicvoidrun() {
String obj ="from myThread";
Message m =h.obtainMessage(1, 1, 1, obj);
h.sendMessage(m);
}
}
}
指令:h=newEventHandler(); 就等于:h = new EventHandler(Looper.myLooper());
它建立了当前线程(Current Thread)的EventHandler对象。于此,是由main线程执行此指令的,所以此EventHandler对象是用来存取main线程的Message Queue。
上述程序将handleMessage()定义于EventHandler类别内,也可以直接定义于ac01类别之内。于是上述程序,也相当于:
//----- Looper_03bb范例-----
//classac01extendsActivity {
// ………
publicvoidonClick(View v) {
switch(v.getId()){
case101:
h=newHandler(){
publicvoidhandleMessage(Message msg) {
((Activity)ctx).setTitle((String)msg.obj);
}};
t=newmyThread();
t.start();
break;
case102:
finish();
break;
}
}
//------------------------------------------------------
classmyThreadextendsThread{
publicvoidrun() {
String obj ="from myThread...";
Message m =h.obtainMessage(1, 1, 1, obj);
h.sendMessage(m);
}
}
}
其执行结果是一样的。
转自:http://www.android1.net/Topic.aspx?BoardID=11&TopicID=631
更多相关文章
- Android的线程使用来更新UI----Thread、Handler、Looper、TimerT
- Android异步消息处理机制(源码分析+面试题)
- SurfaceView 的基本使用
- Android(安卓)之AsyncHttpClient
- android 线程中的ui问题 Handler的基本使用 关于获取动态时间在u
- E/错误(3907): android.view.ViewRootImpl$CalledFromWrongThrea
- Android(安卓)DVM
- 有关Android线程的学习
- Android深入浅出之Binder机制