Handler的使用(一)
Handler基本概念: Handler主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分逐个的在消息队列中将消息取出,然后对消息进行出来,就是发送消息和接收消息不是同步的处理。 这种机制通常用来处理相对耗时比较长的操作。 使用一个例子简单的来介绍一下Handler。 示例1:一个应用程序中有2个按钮(start、end),当点击start按钮时,执行一个线程,这个线程在控制台输出一串字符串,并且每隔3秒再执行一次线程,直到点击end按钮为止,线程停止。 下图为这个应用程序的界面:![](http://dl.iteye.com/upload/attachment/359719/f08201ed-9624-3648-aa61-7f4417b2bccc.jpg)
![](http://dl.iteye.com/upload/attachment/359721/1090a482-7564-3710-b05b-90955bbe7b3f.jpg)
- package android.handler;
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- 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);
- }
- };
- }
上面是一个最简单的例子,下面再看另外一个例子。 示例2:一个应用程序中有一个进度条和一个按钮,当点击按钮后,每隔一秒钟进度条前进一部分。 下图为应用程序的运行效果图:
![](http://dl.iteye.com/upload/attachment/359725/3e7e66a2-36f8-3db4-9daa-0723c4b15e22.jpg)
- package android.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;
- public class ProgressBarHandlerTest extends Activity {
- /** Called when the activity is first created. */
- private ProgressBar progressBar;
- private Button startButton;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- progressBar = (ProgressBar)findViewById(R.id.progressbar);
- startButton = (Button)findViewById(R.id.startButton);
- startButton.setOnClickListener(new ProgressBarOnClickListener());
- }
- class ProgressBarOnClickListener implements OnClickListener{
- public void onClick(View v) {
- //设置进度条为可见状态
- progressBar.setVisibility(View.VISIBLE);
- updateBarHandler.post(updateThread);
- }
- }
- //使用匿名内部类来复写Handler当中的handlerMessage()方法
- Handler updateBarHandler = new Handler(){
- @Override
- public void handleMessage(Message msg) {
- progressBar.setProgress(msg.arg1);
- updateBarHandler.post(updateThread); //将要执行的线程放入到队列当中
- }
- };
- //线程类,该类使用匿名内部类的方式进行声明
- Runnable updateThread = new Runnable(){
- int i = 0;
- public void run() {
- // TODO Auto-generated method stub
- System.out.println("Begin Thread");
- i+=10;
- //得到一个消息对象,Message类是android系统提供的
- Message msg = updateBarHandler.obtainMessage();
- //将Message对象的arg1参数的值设置为i
- msg.arg1 = i; //用arg1、arg2这两个成员变量传递消息,优点是系统性能消耗较少
- try{
- Thread.sleep(1000); //让当前线程休眠1000毫秒
- }catch(InterruptedException ex){
- ex.printStackTrace();
- }
- //将Message对象加入到消息队列当中
- updateBarHandler.sendMessage(msg);
- //如果i的值等于100
- if (i == 100){
- //将线程对象从队列中移除
- updateBarHandler.removeCallbacks(updateThread);
- }
- }
- };
- }
项目源码已经上传到附件了,有需要的可下载。 不知道大家有没有弄明白哈,我自己都写得晕晕乎乎的了,没办法啊语文写作能力不咋地,汗~ 这里其实有一点我没有弄明白,就是当进度条的值等于100的时候,就将线程对象从队列中移除,从而停止线程的运行;这个在示例1中是没有问题的, 当点击end按钮,线程停止;但是在示例2例子中,当进度条的值等于100了,可是却没有停止,还是在继续的运行,每隔一秒就执行一个线程,不知道这是为 什么,研究了好一会儿都没弄明白,希望各位知道的可以跟我说说哈,咱们有机会多探讨探讨、多交流交流!
评论
16 楼 2014-07-24
416849838 写道
回答三楼 不行,因为不能在子线程里更新UI
updateThread里面的run方法是可以更新进度条的,因为这里的操作相当于在UI线程,只要稍微调整一下代码,就可以做到三楼的要求。 15 楼 2014-05-23
用Handler調用Runnable接口應該並不是真的開新線程,只是實現接口而已,Handler把run擺進UI線程的looper運行的,所以即使不用消息,在run用應該也能處理UI的東西。
14 楼 2014-04-24
public void run() { if(i<=100){ // TODO Auto-generated method stub Log.i("QiHang","Begin Thread"); i+=10; //得到一个消息对象,Message类是android系统提供的 Message msg = updateBarHandler.obtainMessage(); //将Message对象的arg1参数的值设置为i msg.arg1 = i; //用arg1、arg2这两个成员变量传递消息,优点是系统性能消耗较少 try{ Thread.sleep(1000); //让当前线程休眠1000毫秒 }catch(InterruptedException ex){ ex.printStackTrace(); } //将Message对象加入到消息队列当中 updateBarHandler.sendMessage(msg); //如果i的值等于100 } else{ //将线程对象从队列中移除 updateBarHandler.removeCallbacks(updateThread); Log.i("QiHang","End Thread"); } } 这样也可以结束
13 楼 2014-02-27
楼主,我来啦
12 楼 2013-08-30
学习了。。。。。
11 楼 2013-08-02
。。。。。。。。。。。。。。。。。。。。
10 楼 2012-12-08
例2会导致updateThread的run方法死循环,原因如下: 当i==100时,执行了下面几行代码 if (i == 100){ //将线程对象从队列中移除 updateBarHandler.removeCallbacks(updateThread); } 看似updateThread线程从线程对象队列中移除,不会再执行了,但是执行这几行代码前执行了下面代码 //将Message对象加入到消息队列当中 updateBarHandler.sendMessage(msg); 这会导致下面的代码被执行 public void handleMessage(Message msg) { progressBar.setProgress(msg.arg1); updateBarHandler.post(updateThread); //将要执行的线程放入到队列当中 } updateThread线程又加到线程对象队列中,updateThread线程永远不会从线程对象队列中移除,updateThread的run方法不断的执行,这就导致了死循环。 解决方案: 将 updateThread的run方法里的 if (i == 100){ //将线程对象从队列中移除 updateBarHandler.removeCallbacks(updateThread); } 这几行代码移到updateBarHandler的handleMessage方法里,修改如下: Handler updateBarHandler = new Handler(){ @Override public void handleMessage(Message msg) { progressBar.setProgress(msg.arg1); if(msg.arg1==100){ updateBarHandler.removeCallbacks(updateThread); }else{ updateBarHandler.post(updateThread); //将要执行的线程放入到队列当中 } } }; 我是通过调试查看代码的执行顺序,发现这个问题的
9 楼 2012-10-27
Handler主要是用于子线程与主线程的通讯,子线程可以把消息发送到主线程的Looper,有主线程来处理。
8 楼 2012-10-25
我觉得Handler大多用来作为线程池中的线程与主线程的通信工具!
7 楼 2011-11-25
回答三楼 不行,因为不能在子线程里更新UI
6 楼 2011-11-20
将 //如果i的值等于100 if (i == 100){ //将线程对象从队列中移除 updateBarHandler.removeCallbacks(updateThread); } 删了,写到如5楼写的那样就行了!!
![](http://byandby.iteye.com/images/smiles/icon_biggrin.gif)
5 楼 2011-09-28
不错,很全面,转了!
4 楼 2011-09-05
- if(msg.arg1>=progressBar.getMax())
- {
- System.out.println("removeCallbacks");
- updateBarHandler.removeCallbacks(updateThread);
- }
- else {
- System.out.println("updateBarHandler.post");
- updateBarHandler.post(updateThread); //将要执行的线程放入到队列当中
- }
3 楼 2011-03-24
请问直接在run方法里面增加进度条的进度不行吗,把i写成一个全局变量。
2 楼 2011-03-16
hehez 写道
- //使用匿名内部类来复写Handler当中的handlerMessage()方法
- Handler updateBarHandler = new Handler(){
- @Override
- public void handleMessage(Message msg) {
- progressBar.setProgress(msg.arg1);
- if(msg.arg1<=progressBar.getMax()) {
- updateBarHandler.removeCallbacks(updateThread);
- }else {
- updateBarHandler.post(updateThread); //将要执行的线程放入到队列当中
- }
- }
- };
1 楼 2011-03-04
- if (i == 100){
- //将线程对象从队列中移除
- updateBarHandler.removeCallbacks(updateThread);
- }
就这段,我也出现和你一样的状况。我在网上搜了好多,有人说是,removeCallbacks只是把updateThread这个线程从队列中移除,但是并没有停止线程。 然后网上也有人提供了一个修正方法,就是在下面这段代码中间
- //使用匿名内部类来复写Handler当中的handlerMessage()方法
- Handler updateBarHandler = new Handler(){
- @Override
- public void handleMessage(Message msg) {
- progressBar.setProgress(msg.arg1);
- updateBarHandler.post(updateThread); //将要执行的线程放入到队列当中
- }
- };
添加一个判断
- //使用匿名内部类来复写Handler当中的handlerMessage()方法
- Handler updateBarHandler = new Handler(){
- @Override
- public void handleMessage(Message msg) {
- progressBar.setProgress(msg.arg1);
- if(msg.arg1<=progressBar.getMax()) {
- updateBarHandler.removeCallbacks(updateThread);
- }else {
- updateBarHandler.post(updateThread); //将要执行的线程放入到队列当中
- }
- }
- };
我试了下,这个是好使的。