1. 复习 Message Queue 的角色
在上一篇里,介绍了 Android 的 Thread 、 Looper 、 Message Queue 和 Handler 四者间之关系。
先复习如下:
l UI 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( 续 )
在上一篇文章里,使用如下程序片段:
// class ac01 extends Activity {
// ………
public void onClick(View v) {
switch (v.getId()){
case 101:
t = new myThread();
t .start();
break ;
case 102:
finish();
break ;
}
}
//------------------------------------------------------
class EHandler extends Handler {
public EHandler(Looper looper) {
super (looper);
}
@Override
public void handleMessage(Message msg) {
tv .setText((String)msg. obj );
}
}
//------------------------------------------------------
class myThread extends Thread{
private EHandler mHandler ;
public void run() {
Looper myLooper, mainLooper;
myLooper = Looper. myLooper ();
mainLooper = Looper. getMainLooper ();
String obj;
if (myLooper == null ){
mHandler = new EHandler(mainLooper);
obj = "current thread has no looper!" ;
}
else {
mHandler = new EHandler(myLooper);
obj = "This is from current thread." ;
}
mHandler .removeMessages(0);
Message m = mHandler .obtainMessage(1, 1, 1, obj);
mHandler .sendMessage(m);
}
}
}
这个 mHandler 定义于 myThread 类别里,而且由子线程执行指令: mHandler = new EHandler(mainLooper);
来创建 EHandler 对象;但是这个 mHandler 确是属于 main 线程的 ( 用来存取主线程的 MessageQueue) ,所以指令:
mHandler .sendMessage(m); 是将 m 丢到主线程的 MessageQueue 里。
此外,我们也可以将 mHandler 定义于 ac01 类别里。如下程序范例:
//----- Looper_03 范例 -----
public class ac01 extends Activity implements OnClickListener {
private final int WC = LinearLayout.LayoutParams. WRAP_CONTENT ;
private final int FP = LinearLayout.LayoutParams. FILL_PARENT ;
public TextView tv ;
private myThread t ;
private Button btn , btn2 ;
EventHandler h ;
Context ctx ;
public void onCreate(Bundle icicle) {
super .onCreate(icicle);
ctx = this ;
LinearLayout layout = new LinearLayout( this );
layout.setOrientation(LinearLayout. VERTICAL );
btn = new Button( this );
btn .setId(101);
btn .setBackgroundResource(R.drawable. heart );
btn .setText( "test looper" );
btn .setOnClickListener( this );
LinearLayout.LayoutParams param =
new LinearLayout.LayoutParams(100,50);
param. topMargin = 10;
layout.addView( btn , param);
btn2 = new Button( this );
btn2 .setId(102);
btn2 .setBackgroundResource(R.drawable. ok_blue );
btn2 .setText( "exit" );
btn2 .setOnClickListener( this );
layout.addView( btn2 , param);
tv = new TextView( this );
tv .setTextColor(Color. WHITE );
tv .setText( "" );
LinearLayout.LayoutParams param2 =
new LinearLayout.LayoutParams( FP , WC );
param2. topMargin = 10;
layout.addView( tv , param2);
setContentView(layout);
}
public void onClick(View v) {
switch (v.getId()){
case 101:
h = new EventHandler(Looper. myLooper ());
t = new myThread();
t .start();
break ;
case 102:
finish();
break ;
}
}
//------------------------------------------------
public class EventHandler extends Handler {
public EventHandler(Looper looper) {
super (looper);
}
@Override
public void handleMessage(Message msg) {
((Activity) ctx ).setTitle((String)msg. obj );
}
}
//------------------------------------------------------
class myThread extends Thread{
public void run() {
String obj = "from myThread" ;
Message m = h .obtainMessage(1, 1, 1, obj);
h .sendMessage(m);
}
}
}
//------------------------------------------------------
指令: h = new EventHandler(Looper. myLooper ());
此 h 是属于 main 线程的 ( 用来存取主线程的 MessageQueue) 。在 myThread 类别里的指令: h .sendMessage(m);
虽然是由子线程执行该指令,还是将 m 丢到主线程的 MessageQueue 里。于是,子线程所执行的 run() 函数,就顺利将 m 丢给主线程 ( 的 Message Queue) ,并触发了主线程去执行 handleMessage() 函数了。显示出画面如下:
图 1
上述的指令:
myLooper = Looper. myLooper ();
mainLooper = Looper. getMainLooper ();
………
mHandler = new EHandler(mainLooper);
………
mHandler = new EHandler(myLooper);
………
都 明显地指明 mHandler 是负责存取哪一个线程的 Message Queue 。不过,有时候并不需要特别指明。例如上述的 onClick() 函数和 EventHandler 类别,可改写为:
//----- Looper_03aa 范例 -----
// class ac01 extends Activity {
// ………
public void onClick(View v) {
switch (v.getId()){
case 101:
h = new EventHandler();
t = new myThread();
t .start();
break ;
case 102:
finish();
break ;
}
}
//------------------------------------------------
public class EventHandler extends Handler {
@Override
public void handleMessage(Message msg) {
((Activity) ctx ).setTitle((String)msg. obj );
}
}
//------------------------------------------------------
class myThread extends Thread{
public void run() {
String obj = "from myThread" ;
Message m = h .obtainMessage(1, 1, 1, obj);
h .sendMessage(m);
}
}
}
指令: h = new EventHandler(); 就等于: h = new EventHandler(Looper.myLooper());
它建立了当前线程 (Current Thread) 的 EventHandler 对象。于此,是由 main 线程执行此指令的,所以此 EventHandler 对象是用来存取 main 线程的 Message Queue 。
上述程序将 handleMessage() 定义于 EventHandler 类别内,也可以直接定义于 ac01 类别之内。于是上述程序,也相当于:
//----- Looper_03bb 范例 -----
// class ac01 extends Activity {
// ………
public void onClick(View v) {
switch (v.getId()){
case 101:
h = new Handler(){
public void handleMessage(Message msg) {
((Activity) ctx ).setTitle((String)msg. obj );
}};
t = new myThread();
t .start();
break ;
case 102:
finish();
break ;
}
}
//------------------------------------------------------
class myThread extends Thread{
public void run() {
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