Android应用中经常需要在多线程中操作UI组件,而多线程操作UI组件会导致安全问题。为了处理这个问题,出现了Handler机制。
使用Handler通常会用到以下函数:
- post(Runnable)
- postAtTime(Runnable,long)
- postDelayed(Runnable long)
- handlerMessage(Message msg)
- sendEmptyMessage(int)
- sendMessage(Message)
- sendMessageDelayed(Message,long)
Message数据传递:
存放数据
Message msg = new Message();
Bundle b = new Bundle();// 存放数据
b.putString("color", "我的");
msg.setData(b);
myHandler.sendMessage(msg);
接收数据
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle b = msg.getData();
String color = b.getString("color");
...
}
最简单的实例:
通过Handler
Handler属于主线程,即UI线程,因此它能够处理UI组件。
public class HandlerTest extends Activity
{
// 定义周期性显示的图片的ID
int[] imageIds = new int[]
{
R.drawable.java,
R.drawable.ee,
R.drawable.ajax,
R.drawable.xml,
R.drawable.classic
};
int currentImageId = 0;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final ImageView show = (ImageView) findViewById(R.id.show);
//位于主线程,相当于普通的函数,等待被调用,负责UI界面的处理。
final Handler myHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
// 如果该消息是本程序所发送的
if (msg.what == 0x1233)
{
// 动态地修改所显示的图片
show.setImageResource(imageIds[currentImageId++% imageIds.length]);
}
}
};
// 新线程,当调用mHandler发送消息时,会自动调用handleMessage()函数
// 定义一个计时器,让该计时器周期性地执行指定任务
new Timer().schedule(new TimerTask()
{
@Override
public void run()
{
// 发送空消息
myHandler.sendEmptyMessage(0x1233);
}
}, 0, 1200);
//回调机制:自己发送Message自己接收。
}
}
public
class
HandlerTest
extends
Activity
{
/** Called when the activity is first created. */
private Button startButton;
private Button endButton;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//根据id获得控件对象
startButton = (Button)findViewById(R.id.startButton);
endButton = (Button)findViewById(R.id.endButton);
//为控件设置监听器
startButton.setOnClickListener(new StartButtonListener());
endButton.setOnClickListener(new EndButtonListener());
}
class StartButtonListener implements OnClickListener{
public void onClick(View v) {
//调用Handler的post()方法,将要执行的线程对象放到队列当中
handler.post(updateThread);
}
}
class EndButtonListener implements OnClickListener{
public void onClick(View v) {
//调用Handler的removeCallbacks()方法,删除队列当中未执行的线程对象
handler.removeCallbacks(updateThread);
}
}
//创建Handler对象
Handler handler = new Handler();
//新建一个线程对象
Runnable updateThread = new Runnable(){
//将要执行的操作写在线程对象的run方法当中
public void run(){
System.out.println("updateThread");
//调用Handler的postDelayed()方法
//这个方法的作用是:将要执行的线程对象放入到队列当中,待时间结束后,运行制定的线程对象
//第一个参数是Runnable类型:将要执行的线程对象
//第二个参数是long类型:延迟的时间,以毫秒为单位
handler.postDelayed(updateThread, 3000);
}
};
}
举例:在新建线程中使用Handler
当点击按钮之后,主线程通过Handler把把数据传递到CalThread 线程,CalThread 线程在处理完之后将结果通过Toast显示出来。
public class CalPrime extends Activity
{
static final String UPPER_NUM = "upper";
EditText etNum;
CalThread calThread;
// 定义一个线程类
class CalThread extends Thread
{
public Handler mHandler;
public void run()
{
Looper.prepare();
mHandler = new Handler()
{
// 定义处理消息的方法
@Override
public void handleMessage(Message msg)
{
if(msg.what == 0x123)
{
int upper = msg.getData().getInt(UPPER_NUM);
List<Integer> nums = new ArrayList<Integer>();
// 计算从2开始、到upper的所有质数
outer:
for (int i = 2 ; i <= upper ; i++)
{
// 用i处于从2开始、到i的平方根的所有数
for (int j = 2 ; j <= Math.sqrt(i) ; j++)
{
// 如果可以整除,表明这个数不是质数
if(i != 2 && i % j == 0)
{
continue outer;
}
}
nums.add(i);
}
// 使用Toast显示统计出来的所有质数
Toast.makeText(CalPrime.this , nums.toString()
, Toast.LENGTH_LONG).show();
}
}
};
Looper.loop();
}
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
etNum = (EditText)findViewById(R.id.etNum);
calThread = new CalThread();
// 启动新线程
calThread.start();
}
// 为按钮的点击事件提供事件处理函数
public void cal(View source)
{
String num = etNum.getText().toString().trim();
if(!"".equals(num)) {
// 创建消息
Message msg = new Message();
msg.what = 0x123;
Bundle bundle = new Bundle();
bundle.putInt(UPPER_NUM, Integer.parseInt(num));
msg.setData(bundle);
// 向新线程中的Handler发送消息
calThread.mHandler.sendMessage(msg);
}else{
tv.setText("Please input a natural number!");
}
}
}
加上新线程将获取的数据传回主线程:
public class CalPrime extends Activity
{
static final String UPPER_NUM = "upper";
EditText etNum;
TextView tv;
CalThread calThread;
Handler myHandler;
// 定义一个线程类
class CalThread extends Thread
{
public Handler mHandler;
public void run()
{
Looper.prepare();
mHandler = new Handler()
{
// 定义处理消息的方法
@Override
public void handleMessage(Message msg)
{
if(msg.what == 0x123)
{
int upper = msg.getData().getInt(UPPER_NUM);
List<Integer> nums = new ArrayList<Integer>();
// 计算从2开始、到upper的所有质数
outer:
for (int i = 2 ; i <= upper ; i++)
{
// 用i处于从2开始、到i的平方根的所有数
for (int j = 2 ; j <= Math.sqrt(i) ; j++)
{
// 如果可以整除,表明这个数不是质数
if(i != 2 && i % j == 0)
{
continue outer;
}
}
nums.add(i);
}
// 使用Toast显示统计出来的所有质数
//Toast.makeText(CalPrime.this , nums.toString(), Toast.LENGTH_LONG).show();
Message mymsg = new Message();
Bundle b = new Bundle();// 存放数据
b.putString("result", nums.toString());
mymsg.setData(b);
mymsg.what=0x1233;
myHandler.sendMessage(mymsg);
}
}
};
Looper.loop();
}
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
etNum = (EditText)findViewById(R.id.etNum);
tv=(TextView)findViewById(R.id.tv);
calThread = new CalThread();
// 启动新线程
calThread.start();
myHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
// 如果该消息是本程序所发送的
if (msg.what == 0x1233)
{
// 动态地修改所显示的图片
Bundle b = msg.getData();
String result = b.getString("result");
tv.setText(result.substring(1,result.length()-1));
}
}
};
}
// 为按钮的点击事件提供事件处理函数
public void cal(View source)
{
String num = etNum.getText().toString().trim();
if(!"".equals(num)) {
// 创建消息
Message msg = new Message();
msg.what = 0x123;
Bundle bundle = new Bundle();
bundle.putInt(UPPER_NUM, Integer.parseInt(num));
msg.setData(bundle);
// 向新线程中的Handler发送消息
calThread.mHandler.sendMessage(msg);
}else{
tv.setText("Please input a natural number!");
}
}
}