andriod提供了Handler 和 Looper 来满足线程间的通信。Handler先进先出原则。Looper类用来管理特定线程内对象之间的消息交换(MessageExchange)。
1)Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。
2)Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从Message Queue取出)所送来的消息。
3) Message Queue(消息队列):用来存放线程放入的消息。
4)线程:UIthread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue。
1.Handler创建消息
每一个消息都需要被指定的Handler处理,通过Handler创建消息便可以完成此功能。Android消息机制中引入了消息池。Handler创建消息时首先查询消息池中是否有消息存在,如果有直接从消息池中取得,如果没有则重新初始化一个消息实例。使用消息池的好处是:消息不被使用时,并不作为垃圾回收,而是放入消息池,可供下次Handler创建消息时使用。消息池提高了消息对象的复用,减少系统垃圾回收的次数。消息的创建流程如图所示。

2.Handler发送消息
UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper,该Looper与UI主线程一一对应。使用ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的Looper。Looper初始化的时候会创建一个消息队列MessageQueue。至此,主线程、消息循环、消息队列之间的关系是1:1:1。
Handler、Looper、MessageQueue的初始化流程如图所示:
3.Handler处理消息
UI主线程通过Looper循环查询消息队列UI_MQ,当发现有消息存在时会将消息从消息队列中取出。首先分析消息,通过消息的参数判断该消息对应的Handler,然后将消息分发到指定的Handler进行处理。
子线程通过Handler、Looper与UI主线程通信的流程如图所示。
一、Handler介绍
在一个线程中存在一个消息队列,当消息队列中存在消息时,Handler就会处理这些消息;我们考虑一下这种场景:
我们要执行一个耗时很长的业务,执行完后要返回一个结果显示在TextView上,我们在主线程中执行这种业务是否合理呢?
显然是不合理的,因此我们会想到把业务放到子线程中执行,但是Android有个规定:所有更新UI的操作全要在主线程中完成,因此我们要做的就是把子线程执行完的结果传到主线程中并显示,这就需要Handler的帮忙;
比如ProgressBar、TextView的使用都会用到Handler;
当应用5秒内没有响应用户的输入,则会抛出以下错误:
Handler的原理如下:
模板代码:
- package org.xiazdong.handler;
- public class SampleActivity extends Activity {
- private Button button;
- private Handler handler = new Handler(){
- @Override
- public void handleMessage(Message msg) {
- if(msg.what == 1){
- //更新UI
- }
- if(msg.what == 2){
- //更新UI
- }
- }
- };
- private OnClickListener listener = new OnClickListener() {
- class ServiceThread extends Thread{
- private ServiceListener serviceListener = new ServiceListener() {
- @Override
- public void onService(int current) {//服务监听器
- //一边执行,一边发送消息给主线程
- handler.sendMessage(msg);
- }
- };
- @Override
- public void run() {
- //执行业务
- }
- }
- @Override
- public void onClick(View v) {
- ServiceThread thread = new ServiceThread(); //子线程执行业务
- thread.start();
- }
- };
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- button = (Button)this.findViewById(R.id.button);
- button.setOnClickListener(listener);
- }
- }
二、实例
程序说明:
执行一个业务:从零开始,每隔3秒加1,直到加到5,返回结果5,并通过ProgressBar实时显示加到几了;
程序类声明:
(1)ServiceListener接口:此接口专门用来监听服务进行,并根据服务进行执行逻辑
- onService(int current);
(2)Service:此类为业务类,执行此业务;
执行效果:点击开始执行,则每三秒进度条加1,等到进度满时,显示result=5;
ServiceListener.java
- package org.xiazdong.handler;
- /**
- * Service监听器
- * @author xiazdong
- *
- */
- public interface ServiceListener {
- public void onService(int current);
- }
Service.java
- package org.xiazdong.handler;
- public class Service {
- private int sum = 5;
- private int current = 0;
- public void sum(ServiceListener listener)throws Exception{
- while(current<sum){
- Thread.sleep(3000);
- current++;
- listener.onService(current);
- }
- }
- }
MainActivity.java
- package org.xiazdong.handler;
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.ProgressBar;
- import android.widget.TextView;
- public class MainActivity extends Activity {
- private TextView textView;
- private Button button;
- private ProgressBar progressBar;
- private Handler handler = new Handler(){
- @Override
- public void handleMessage(Message msg) {
- if(msg.what == 1){
- int current = msg.getData().getInt("current");
- progressBar.setProgress(current);
- }
- if(msg.what == 2){
- int result = msg.getData().getInt("result");
- textView.setText("result="+result);
- }
- }
- };
- private OnClickListener listener = new OnClickListener() {
- class ServiceThread extends Thread{
- private ServiceListener serviceListener = new ServiceListener() {
- @Override
- public void onService(int current) {//服务监听器
- Message msg = new Message();
- msg.what = 1;
- msg.getData().putInt("current", current);
- handler.sendMessage(msg);
- }
- };
- @Override
- public void run() {
- Service service = new Service();
- progressBar.setMax(5); //设置最大进度
- progressBar.setProgress(0); //初始进度为0
- try {
- service.sum(serviceListener); //执行业务,并传入监听器,监听业务的执行
- //当执行完成,发送最后的结果5给TextView
- Message msg = new Message();
- msg.what = 2;
- msg.getData().putInt("result", 5);
- handler.sendMessage(msg);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- @Override
- public void onClick(View v) {
- ServiceThread thread = new ServiceThread(); //子线程执行业务
- thread.start();
- }
- };
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- textView = (TextView)this.findViewById(R.id.textView);
- button = (Button)this.findViewById(R.id.button);
- progressBar = (ProgressBar)this.findViewById(R.id.progressBar);
- button.setOnClickListener(listener);
- }
- }
实例演示
package com.example.handlertest;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
/**
* 通过一个demo来讲解下几种Handler处理的情况
*
*
*
* 为了引入Handler消息机制,我们必须先知道“同步”和“异步”通信的差别
*
* “同步”通信: 比如 我打电话给小明,跟小明进行对话,我必须等到和小明结束通话之后,才能再拨打其他人的电话
* (同步就是发送一个请求之后,什么事都不做,一直等到结果返回后才继续做下面的事情)
*
* "异步"通信: 比如 我给几个同学发送E-mail邮件,全部发送过去之后,不需要在这边等他们回复,
我还可以去做别的事情,他们回复的时候,邮箱系统会通知我
* (异步就是发出请求之后,这个请求完成之后,通过状态,通知或者回调等方式来通知调用者处理的结果)
*
*
* Handler机制的产生原因: 一个应用程序开启之后,首先会开启一个UI线程(主线程),顾名思义是用来管理界面中UI控件的,
* 并对事件进行分发,比如一个Button的点击事件,android把事件分发到对应的Button上,来响应用户操作
* 但由于用户有可能需要做一些耗时的操作(下载文件),但是android如果5秒钟界面没反应的话,就会提示
* 用户关闭应用程序了,所以这时候需要把这些耗时的操作放在 子线程 中处理,子线程处理完成之后再去更新
* UI线程中的界面,而Android的UI线程又是不安全的,这样意味着子线程中无法直接更新UI线程的界面,
* 因此Android中设计了Handler来解决这个问题!
*
* 解决方法: Handler运行在UI线程中,它与子线程可通过Message对象来传递数据,这时候,handler就承担了接收子线程
* 传来的Message对象的责任,从而配合UI线程更新UI。
*
*
* Handler消息机制:
*
*
* 1.handler存取消息的原理:
*
* Handler允许发送并处理Message消息,Message消息通过主线程的MessageQueue消息队列相关联的Message和
* Runnable对象进行存取,当创建一个新的handler时(在主线程中创建),handler就属于当前主线程,主线程的
* MessageQueue也同步创建,Handler会绑定到该主线程/消息队列中,这样,handler就可以通过主线程的消息队列
* 发送和接收Message消息对象了
*
*
* 2.Handler消息处理机制的几种情况[下面用代码来说明这几种情况]: 2.1 button1: 主线程中做Handler 2.2
button2:
* 子线程中做Handler 2.3 button3: 把主线程创建的Handler传递给其他线程完成消息处理 2.4 button4:
* 在其他线程中更新UI线程界面,它抛出异常,我们看看哈~!
*
*
*
*
发送Message不会阻塞线程(异步),而接收消息处理会阻塞线程[当Handler处理完一个Message对象后才会接着去取下一个消息进行处理](同步)
*
*
* 2013年09月11日23:37:08
*
* @author xiaoyaomeng
*
*/
public class MainActivity extends Activity implements OnClickListener {
HandlerDemo myHandlerDemo = null;// 该对象用于主线程中创建handler
Button button1 = null;
Button button2 = null;
Button button3 = null;
Button button4 = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1 = (Button) findViewById(R.id.button1);
button2 = (Button) findViewById(R.id.button2);
button3 = (Button) findViewById(R.id.button3);
button4 = (Button) findViewById(R.id.button4);
button1.setOnClickListener(this);
button2.setOnClickListener(this);
button3.setOnClickListener(this);
button4.setOnClickListener(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is
present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
handlerDealMessage(v.getId());
}
private void handlerDealMessage(int id) {
// TODO Auto-generated method stub
switch (id) {
case R.id.button1: {
// 主线程中创建Handler实例
myHandlerDemo = new HandlerDemo();
Message message = myHandlerDemo.obtainMessage(1,
(Object) ("Hello,My name is Handler1~~"));
message.sendToTarget();// Handler发送消息,会对应发送到这个和这个Handler绑定的UI线程做处理
}
break;
case R.id.button2: {
MyThread myThread = new MyThread();
myThread.start();
}
break;
case R.id.button3: {
myHandlerDemo = new HandlerDemo();
OtherThread otherThread = new OtherThread(myHandlerDemo);
otherThread.start();
}
break;
case R.id.button4: {
errorHandlerThread errorHandlerThread = new errorHandlerThread(
button4);
errorHandlerThread.start();
}
break;
default:
break;
}
}
/*
* MyThread 是内部类,子线程
*/
private class MyThread extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
// 1.error: 只能在UI线程中采用不带Looper对象创建Handler对象,所以此处会报异常
// myHandlerDemo = new HandlerDemo();
// 2.error: Looper.myLooper获取的Looper是null,所以也会报异常
// myHandlerDemo = new HandlerDemo(Looper.myLooper());
//
通过Looper.getMainLooper()可以得到父类的looper,所以可以成功创建handler对象并绑定MessageQueue
myHandlerDemo = new HandlerDemo(Looper.getMainLooper());
Message message = myHandlerDemo.obtainMessage(2,
(Object) ("Hello,My name is Handler2~~"));
message.sendToTarget();
}
}
private/**
* 创建一个Handler
*
* @author xiaoyaomeng
*
*/
class HandlerDemo extends Handler {
/* 在UI线程中创建handler时,可以直接调用这个构造函数 */
public HandlerDemo() {
super();
// TODO Auto-generated constructor stub
}
/* 在子线程中创建一个Handler需要用到这个构造函数,否则报错 */
public HandlerDemo(Looper looper) {
super(looper);
// TODO Auto-generated constructor stub
}
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
switch (msg.what) {
case 1: {
button1.setText(msg.obj.toString());
}
break;
case 2: {
button2.setText(msg.obj.toString());
}
break;
case 3: {
button3.setText(msg.obj.toString());
}
break;
default:
break;
}
}
}
}
/**
*
* 其他线程的类,用来接收一个handler,并在线程中 用这个handler发送消息
*
* @author xiaoyaomeng
*
*/
class OtherThread extends Thread {
private Handler mHandler;
public OtherThread(Handler handler) {
// TODO Auto-generated constructor stub
mHandler = handler;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
Message message = mHandler.obtainMessage(3,
(Object) ("Hello,My name is Handler3~~"));
message.sendToTarget();
}
}
/**
* 测试错误报错的线程
*
* @author xiaoyaomeng
*
*/
class errorHandlerThread extends Thread {
Button button = null;
public errorHandlerThread(Button button) {
// TODO Auto-generated constructor stub
this.button = button;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
button.setText("hahahaha~~~");
}
}