http://dz.sdut.edu.cn/blog/subaochen/?p=158
Android中的Handler提供了线程之间通讯的简便手段,如下图所示:
Android的主线程(即UI线程)内部实现了消息队列机制,即一个主线程会自动创建一个消息队列(显然也只有一个消息队列),同时创建一个读取消息队列的Looper对象。主线程的所有用户交互都通过消息队列和Looper对象来实现:当有新的消息进入消息队列时,Looper会及时读取消息并调用相应的处理逻辑(更新用户界面)。
当其他线程希望更新用户界面时,可以通过Handler提供的sendMessage方法在消息队列中放入一个消息(Message对象,可以携带大量信息),这样Looper即可以及时获取该消息,并调用Handler相应的handleMessage方法处理该消息,这样就实现了线程之间的通讯。由此可以看出,Handler在线程通讯中起到了一个枢纽作用:Handler即负责和消息队列打交道,也负责处理相应的消息,其他线程通过Handler和主线程通讯,就可以不需要考虑和主线程的竞争和同步问题,极大的简化了线程的使用。
下面的示例代码演示了一个每隔1秒显示一条消息在主界面:
public class MainActivity extends Activity {
private TextView label;
private static int UPDATE = 1;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1) {
label.setText(String.valueOf(msg.obj));
super.handleMessage(msg);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
label = (TextView) findViewById(R.id.label);
new Thread() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Message msg = new Message();
msg.what = UPDATE;
msg.obj = "当前循环变量:" + i;
handler.sendMessage(msg);
}
}
}.start();
}
在上面的例子中,所谓的其他线程其实主线程的子线程,下面一个例子则演示了完全不同的两个组件通过Handler实现的交互:一个Service每隔1秒产生一个随机数,然后在主线程显示出来:
ServiceDemo.java文件:
public class ServiceDemo extends Service {
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
private Thread workThread;
@Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "(1) onCreate()",
Toast.LENGTH_LONG).show();
workThread = new Thread(null,backgroudWork,"WorkThread");
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Toast.makeText(this, "(2) onStart()",
Toast.LENGTH_SHORT).show();
if (!workThread.isAlive()){
workThread.start();
}
}
@Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "(3) onDestroy()",
Toast.LENGTH_SHORT).show();
workThread.interrupt();
}
private Runnable backgroudWork = new Runnable(){
@Override
public void run() {
try {
while(!Thread.interrupted()){
double randomDouble = Math.random();
MainActivity.updateGUI(randomDouble);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
MainActivity.java文件:
public class MainActivity extends Activity {
private static TextView label;
private static int UPDATE = 1;
protected static Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1) {
label.setText(String.valueOf(msg.obj));
super.handleMessage(msg);
}
}
};
public static void updateGUI(double doubleRadom){
Message msg = new Message();
msg.what = UPDATE;
msg.obj = "当前随机数:" + doubleRadom;
handler.sendMessage(msg);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
label = (TextView) findViewById(R.id.label);
final Intent serviceIntent = new Intent(this, ServiceDemo.class);
startService(serviceIntent);
}
}
可以看出,为了实现在两个组件间的通讯,主要的变化是:
- 将Handler对象定义为static类型的,便于在其他组件访问handler
- 在主线程中实现一个静态的updateGUI方法,以便通过调用handler.sendMessage添加一个消息到消息队列中
- 在Service的线程中,调用主线程的updateGUI并传入适当的参数
Handler和消息循环机制的设计很巧妙,在WEB应用和企业级应用中是否可以借鉴呢?