1. Message Queue 的角色
l 在你的 Android 程序里,新创建一个线程,或称线程 (Thread) 时,并不会自动建立其 Message Loop 。
l Android 里并没有 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 = new EventHandler(Looper. myLooper ()) ; 可创建用来处理目前线程的 Handler 对象;其中, EventHandler 是 Handler 的子类别。
l 使用 mHandler = new EventHandler(Looper. getMainLooper() ) ; 可创建用来处理 main 线程的 Handler 对象;其中, EventHandler 是 Handler 的子类别。
2. 范例之一: Looper 类之角色
Looper 类别用来管理特定线程内对象之间的消息交换 (Message Exchange) 。你的应用程序可以创建许多个线程,或称线程 (Thread) 。而一个线程可以实例化许多个对象,这些对象之间常常需要互相交换消息。如果有这种需要,您可以替线程创建一个 Looper 类对象,来处理信息交换的管理工作。 Looper 对象会建立一个 MessageQueue 数据结构来存放各对象传来的消息 ( 包括 UI 事件或 System 事件等 ) 。如下图:
每一个线程 (Thread ,或称「线程」 ) 里可含有一个 Looper 对象以及一个 MessageQueue 数据结构 。在你的应用程序里,可以 定义 Handler 的子类别来接收 Looper 所送出的消息 。
//----- Looper_01 范例 -----
package com.misoo.kx04;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
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 EventHandler mHandler ;
private Button btn , btn2 , btn3 ;
public void onCreate(Bundle icicle) {
super .onCreate(icicle);
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: Looper looper;
looper = Looper. myLooper ();
mHandler = new EventHandler(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 ;
case 102:
finish();
break ;
}
}
//------------------------------------------------------
class EventHandler extends Handler{
public EventHandler(Looper looper) {
super (looper);
}
@Override
public void handleMessage(Message msg) {
tv .setText((String)msg. obj );
}
}
}
//-------------------------------------------------------
说明:
程序启动时,当前线程 ( 即主线程 , main thread) 已创建了一个 Looper 对象,并且有了一个 MessageQueue 数据结构。
指令: looper = Looper. myLooper (); 调用 Looper 类的静态 myLooper() 函数,以取得目前线程里的 Looper 对象引用。
指令: mHandler = new EventHandler(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 范例 -----
package com.misoo.kx04;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
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 , btn3 ;
public void onCreate(Bundle icicle) {
//文章长度有限,代码请参考上例
}
public void onClick(View v) {
switch (v.getId()){
case 101:
t = new myThread();
t .start();
break ;
case 102:
finish();
break ;
}
}
//------------------------------------------------------
class EHandler extends Handler { //文章长度有限,代码请参考上例
//------------------------------------------------------
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);
}
}
}
Android 会自动替主线程建立 Message Queue 。 在这个 子线程里并没有建立 Message Queue 。所以, myLooper 值为 null ,而 mainLooper 则指向主线程里的 Looper 对象。于是,执行到指令:
mHandler = new EHandler(mainLooper); 此 mHandler 属于主线程 。
指令: mHandler .sendMessage(m);
就将消息 m 存入到主线程的 Message Queue 里。 mainLooper 看到 Message Queue 里有消息,就会处理之,于是由主线程执行到 mHandler 的 handleMessage() 函数来处理消息。此程序输出画面为: