android Handler的使用(一)

Handler的使用(一)

Handler基本概念:
Handler主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分逐个的在消息队列中将消息取出,然后对消息进行出来,就是发送消息和接收消息不是同步的处理。
这种机制通常用来处理相对耗时比较长的操作。

使用一个例子简单的来介绍一下Handler。
示例1:一个应用程序中有2个按钮(start、end),当点击start按钮时,执行一个线程,这个线程在控制台输出一串字符串,并且每隔3秒再执行一次线程,直到点击end按钮为止,线程停止。
下图为这个应用程序的界面:



下图为执行程序时控制台的输出:



开发步骤:
1、 新建一个Android应用程序
2、 在布局文件中添加2个Button控件标签,并为其设置属性和值
3、 在Activity中,声明控件变量并根据id获得控件对象
4、 在Activity中,创建一个Handler对象
5、 在Activity中,创建一个Runnable对象
a) 以匿名内部类的方式
b) 将要执行的操作写在Runnable对象中的run()方法中
i. 打印出一句话
ii. 调用Runnable对象的postDelayed()方法
6、 在Activity中,编写start按钮需要的监听器,并绑定
a) 在这个监听器的Onclick()方法中,调用Handler的post()方法,将要执行的线程对象放到队列当中。
7、 在Activity中,编写end按钮需要的监听器,并帮定
a) 在这个监听器的Onclick()方法中,调用Handler的removeCallbacks ()方法,删除队列当中未执行的线程对象。
b)
下面是Activity的代码:

Java代码  收藏代码
  1. package android.handler;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.os.Handler;  
  6. import android.view.View;  
  7. import android.view.View.OnClickListener;  
  8. import android.widget.Button;  
  9.   
  10. public class HandlerTest extends Activity {  
  11.     /** Called when the activity is first created. */  
  12.     private Button startButton;  
  13.     private Button endButton;  
  14.       
  15.     @Override  
  16.     public void onCreate(Bundle savedInstanceState) {  
  17.         super.onCreate(savedInstanceState);  
  18.         setContentView(R.layout.main);  
  19.         //根据id获得控件对象  
  20.         startButton = (Button)findViewById(R.id.startButton);  
  21.         endButton = (Button)findViewById(R.id.endButton);  
  22.         //为控件设置监听器  
  23.         startButton.setOnClickListener(new StartButtonListener());  
  24.         endButton.setOnClickListener(new EndButtonListener());  
  25.     }  
  26.       
  27.     class StartButtonListener implements OnClickListener{  
  28.         public void onClick(View v) {  
  29.             //调用Handler的post()方法,将要执行的线程对象放到队列当中  
  30.             handler.post(updateThread);  
  31.         }  
  32.     }  
  33.       
  34.     class EndButtonListener implements OnClickListener{  
  35.         public void onClick(View v) {  
  36.             //调用Handler的removeCallbacks()方法,删除队列当中未执行的线程对象  
  37.             handler.removeCallbacks(updateThread);  
  38.         }  
  39.           
  40.     }  
  41.       
  42.     //创建Handler对象  
  43.     Handler handler = new Handler();  
  44.     //新建一个线程对象  
  45.     Runnable updateThread = new Runnable(){  
  46.         //将要执行的操作写在线程对象的run方法当中  
  47.         public void run(){  
  48.             System.out.println("updateThread");  
  49.             //调用Handler的postDelayed()方法  
  50.             //这个方法的作用是:将要执行的线程对象放入到队列当中,待时间结束后,运行制定的线程对象  
  51.             //第一个参数是Runnable类型:将要执行的线程对象  
  52.             //第二个参数是long类型:延迟的时间,以毫秒为单位  
  53.             handler.postDelayed(updateThread, 3000);  
  54.         }  
  55.     };  
  56. }  


上面是一个最简单的例子,下面再看另外一个例子。
示例2:一个应用程序中有一个进度条和一个按钮,当点击按钮后,每隔一秒钟进度条前进一部分。
下图为应用程序的运行效果图:



开发步骤:
1、 新建一个Android应用程序
2、 在布局文件中添加一个progressBar和一个Button,并为其设置属性和值
3、 在Activity中,声明控件变量并根据id获得控件对象
4、 创建线程对象
a) 通过匿名内部类的方式
b) 在编写完了5、6步之后再来继续编写这个线程对象里的操作
i. 声明一个变量用来设置进度条的进度
ii. 重写线程类的run方法(),里面编写要执行的操作
1. 打印一个字符串
2. 进度条的值增加
3. 得到一个消息对象
4. 设置消息对象arg1的值
5. 让线程休眠一秒钟
6. 将消息对象放入到消息队列中
7. 判断,如果进度条的值等于100,则将线程对象从队列中移除。
5、 创建Handler对象
a) 与示例1不同的地方是,这里是通过匿名内部类的方式来声明的,而示例1是直接new出来的对象
b) 重写Handler对象的handlerMessage(Message msg)方法
i. 这个方法传入了一个Message对象,即消息对象,首先设置进度条的进度(这个值是Messag对象里面的一个成员变量arg1)。
ii. 将要执行的线程对象放入到队列当中
6、 编写Button需要的监听器,并绑定
a) 设置进度条为显示状态
b) 将要执行的线程对象放入到队列当中
下面是Activity的代码:

Java代码  收藏代码
  1. package android.handler;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.os.Handler;  
  6. import android.os.Message;  
  7. import android.view.View;  
  8. import android.view.View.OnClickListener;  
  9. import android.widget.Button;  
  10. import android.widget.ProgressBar;  
  11.   
  12. public class ProgressBarHandlerTest extends Activity {  
  13.     /** Called when the activity is first created. */  
  14.       
  15.     private ProgressBar progressBar;  
  16.     private Button startButton;  
  17.       
  18.     @Override  
  19.     public void onCreate(Bundle savedInstanceState) {  
  20.         super.onCreate(savedInstanceState);  
  21.         setContentView(R.layout.main);  
  22.           
  23.         progressBar = (ProgressBar)findViewById(R.id.progressbar);  
  24.         startButton = (Button)findViewById(R.id.startButton);  
  25.           
  26.         startButton.setOnClickListener(new ProgressBarOnClickListener());  
  27.     }  
  28.       
  29.     class ProgressBarOnClickListener implements OnClickListener{  
  30.         public void onClick(View v) {  
  31.             //设置进度条为可见状态  
  32.             progressBar.setVisibility(View.VISIBLE);  
  33.             updateBarHandler.post(updateThread);  
  34.         }  
  35.     }  
  36.       
  37.     //使用匿名内部类来复写Handler当中的handlerMessage()方法  
  38.     Handler updateBarHandler = new Handler(){  
  39.         @Override  
  40.         public void handleMessage(Message msg) {  
  41.             progressBar.setProgress(msg.arg1);  
  42.             updateBarHandler.post(updateThread);    //将要执行的线程放入到队列当中  
  43.         }  
  44.     };  
  45.       
  46.     //线程类,该类使用匿名内部类的方式进行声明  
  47.     Runnable updateThread = new Runnable(){  
  48.         int i = 0;  
  49.         public void run() {  
  50.             // TODO Auto-generated method stub  
  51.             System.out.println("Begin Thread");  
  52.             i+=10;  
  53.             //得到一个消息对象,Message类是android系统提供的  
  54.             Message msg = updateBarHandler.obtainMessage();  
  55.             //将Message对象的arg1参数的值设置为i  
  56.             msg.arg1 = i;   //用arg1、arg2这两个成员变量传递消息,优点是系统性能消耗较少  
  57.             try{  
  58.                 Thread.sleep(1000); //让当前线程休眠1000毫秒  
  59.             }catch(InterruptedException ex){  
  60.                 ex.printStackTrace();  
  61.             }  
  62.             //将Message对象加入到消息队列当中  
  63.             updateBarHandler.sendMessage(msg);  
  64.             //如果i的值等于100  
  65.             if (i == 100){  
  66.                 //将线程对象从队列中移除  
  67.                 updateBarHandler.removeCallbacks(updateThread);   
  68.             }  
  69.         }  
  70.     };  
  71. }  


项目源码已经上传到附件了,有需要的可下载。

不知道大家有没有弄明白哈,我自己都写得晕晕乎乎的了,没办法啊语文写作能力不咋地,汗~



这里其实有一点我没有弄明白,就是当进度条的值等于100的时候,就将线程对象从队列中移除,从而停止线程的运行;这个在示例1中是没有问题的, 当点击end按钮,线程停止;但是在示例2例子中,当进度条的值等于100了,可是却没有停止,还是在继续的运行,每隔一秒就执行一个线程,不知道这是为 什么,研究了好一会儿都没弄明白,希望各位知道的可以跟我说说哈,咱们有机会多探讨探讨、多交流交流!

 

评论

16 楼 qiongqiong421122 2014-07-24  
416849838 写道
回答三楼  不行,因为不能在子线程里更新UI

updateThread里面的run方法是可以更新进度条的,因为这里的操作相当于在UI线程,只要稍微调整一下代码,就可以做到三楼的要求。
15 楼 geniuz 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 楼 xh194910 2014-02-27  
楼主,我来啦
12 楼 yong7356 2013-08-30  
学习了。。。。。
11 楼 yong7356 2013-08-02  
。。。。。。。。。。。。。。。。。。。。
10 楼 mengrenfeixiang 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 楼 jkzhao 2012-10-27  
Handler主要是用于子线程与主线程的通讯,子线程可以把消息发送到主线程的Looper,有主线程来处理。
8 楼 tracydeerge 2012-10-25  
我觉得Handler大多用来作为线程池中的线程与主线程的通信工具!
7 楼 416849838 2011-11-25  
回答三楼  不行,因为不能在子线程里更新UI
6 楼 zhangjm123 2011-11-20  
将 //如果i的值等于100 
            if (i == 100){ 
                //将线程对象从队列中移除 
                updateBarHandler.removeCallbacks(updateThread);  
            } 
删了,写到如5楼写的那样就行了!!
5 楼 sserf 2011-09-28  
不错,很全面,转了!
4 楼 cj83226 2011-09-05  
Java代码  收藏代码
  1. if(msg.arg1>=progressBar.getMax())   
  2.             {    
  3.                 System.out.println("removeCallbacks");  
  4.                 updateBarHandler.removeCallbacks(updateThread);        
  5.                 
  6.             }  
  7.             else {    
  8.                 System.out.println("updateBarHandler.post");  
  9.                 updateBarHandler.post(updateThread);    //将要执行的线程放入到队列当中  
  10.             }  

应该是这样吧。。。。
3 楼 wjb_forward 2011-03-24  
请问直接在run方法里面增加进度条的进度不行吗,把i写成一个全局变量。
2 楼 meng_fan_zhen 2011-03-16  
hehez 写道
Java代码  收藏代码
  1. //使用匿名内部类来复写Handler当中的handlerMessage()方法     
  2.     Handler updateBarHandler = new Handler(){     
  3.         @Override    
  4.         public void handleMessage(Message msg) {     
  5.             progressBar.setProgress(msg.arg1);    
  6.  if(msg.arg1<=progressBar.getMax()) {  
  7. updateBarHandler.removeCallbacks(updateThread);      
  8.   
  9.            }else {  
  10. updateBarHandler.post(updateThread);    //将要执行的线程放入到队列当中     
  11.   
  12. }  
  13.         }     
  14.    };  



我试了下,这个是好使的。

1楼的判断条件是不是正好写反了?
1 楼 hehez 2011-03-04  
Java代码  收藏代码
  1. if (i == 100){     
  2.                 //将线程对象从队列中移除     
  3.                updateBarHandler.removeCallbacks(updateThread);      
  4.             }     



就这段,我也出现和你一样的状况。我在网上搜了好多,有人说是,removeCallbacks只是把updateThread这个线程从队列中移除,但是并没有停止线程。
然后网上也有人提供了一个修正方法,就是在下面这段代码中间

Java代码  收藏代码
  1. //使用匿名内部类来复写Handler当中的handlerMessage()方法     
  2.     Handler updateBarHandler = new Handler(){     
  3.         @Override    
  4.         public void handleMessage(Message msg) {     
  5.             progressBar.setProgress(msg.arg1);     
  6.            updateBarHandler.post(updateThread);    //将要执行的线程放入到队列当中     
  7.         }     
  8.    };  



添加一个判断

Java代码  收藏代码
  1. //使用匿名内部类来复写Handler当中的handlerMessage()方法     
  2.     Handler updateBarHandler = new Handler(){     
  3.         @Override    
  4.         public void handleMessage(Message msg) {     
  5.             progressBar.setProgress(msg.arg1);    
  6.  if(msg.arg1<=progressBar.getMax()) {  
  7. updateBarHandler.removeCallbacks(updateThread);      
  8.   
  9.            }else {  
  10. updateBarHandler.post(updateThread);    //将要执行的线程放入到队列当中     
  11.   
  12. }  
  13.         }     
  14.    };  




我试了下,这个是好使的。

转载于:https://www.cnblogs.com/xgjblog/p/3881470.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/432412.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php和python的多线程,Python多线程以及线程锁简单理解(代码)

本篇文章给大家带来的内容是关于Python多线程以及线程锁简单理解(代码)&#xff0c;有一定的参考价值&#xff0c;有需要的朋友可以参考一下&#xff0c;希望对你有所帮助。多线程threading 模块创建线程创建自己的线程类线程通信线程同步互斥方法线程锁需要了解&#xff01;&a…

现实地形导入UE4全流程

制作地形方法很多&#xff0c;今天给大家分享一种原创野套路。此方法特点是将现实中的地形于UE4中呈现&#xff0c;而不是手动绘制地形。首先从地理空间数据云获得指定区域的地理数据&#xff0c;然后使用GlobalMapper更准确选出区域并把数据转换成WorldMachine可识别的格式&am…

php对象存储hadoop存储,三个理由告诉你对象存储替换HDFS还不错

Hadoop使企业能够对庞大的非结构化数据集进行大规模分析处理。这个数据集可以包含数以百万计&#xff0c;甚至数十亿个需要读取的文件。为了降低成本并提高数据处理性能&#xff0c;数据和应用程序应该存在于相同的物理硬件上。这样做使数据无需移动&#xff0c;就地处理&#…

Web请求中同步与异步的区别

普通的B/S模式就是同步&#xff0c;而AJAX技术就是异步&#xff0c;当然XMLHttpReques有同步的选项。 同步&#xff1a;提交请求->等待服务器处理->处理完毕返回。这个期间客户端浏览器不能干任何事。 异步: 请求通过事件触发->服务器处理&#xff08;这是浏览器仍然可…

大地形pawn抖动问题

在pawn的event tick里调用下面函数即可

php蓝牙连接不上,蓝牙音响连接不上手机怎么办 两种方法轻松解决连接问题

我们听歌一般用耳机和音响。现在蓝牙音频越来越普及&#xff0c;但毕竟是无线产品。信号不时中断或不连接是正常的。蓝牙音频连不上手机真的很头疼。出现这种情况的原因是什么&#xff0c;如何解决&#xff1f;为什么蓝牙音频不能连接到手机1.蓝牙音频没有进入匹配状态&#xf…

Bootstrap页面布局16 - BS导航菜单和其响应式布局以及导航中的下拉菜单

代码&#xff1a; <div classcontainer-fluid><h2 classpage-header>导航</h2><!--    .navrbar navbar-fixed-top:导航固定显示在顶部&#xff0c;对应的navbar-fixed-bottom:导航固定显示在页面底部    .brand:提示文字或者主题    .active…

HMI使用自定义控件流程

1.定义控件ID号&#xff0c;以FO_COMP_CUSTOM为基数#define SCENEENTITY_SIMULATOR_SHAPEFO_COMP_CUSTOM 2102.编写控件类&#xff0c;并继承于CFOBitmapShape 具体实现可以在程序中找例子&#xff0c;重新OnDraw3d这个虚函数来实现控件的绘制3. 在MainFrm.cpp中&#xff0c;在…

nginx 怎么重新编译安装mysql,centos 下 编译安装 nginx + mysql + php 服务

centos 下编译安装nginx mysql php 服务1、安装nginx1.1、安装依赖包yum install wget make gcc gcc-c pcre-devel openssl-devel -y yum install ncurses-devel libtool zilib-devel -y1.2、创建www用户useradd www -s /sbin/nologin -M1.3、创建目录mkdir -p /var/log/ngin…

hdu 1874(Dijkstra + Floyd)

链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid1874 畅通工程续 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 27692 Accepted Submission(s): 10019 Problem Description某省自从实行了很多年…

php原生session,利用Memcached在php下实现session机制 替换PHP的原生session支持

方法文件session实现文件:memcachedsession.php实现原理(也是PHP内部session的实现原理)&#xff1a;1.先判断客户端有没有sessionid&#xff0c;a.没有就添加一个sessionid给客户端&#xff0c;通常是32位hash码&#xff0c;同时初始化一个数组做session容器b.如果客户端有ses…

Web 开发中很实用的10个效果【附源码下载】

在工作中&#xff0c;我们可能会用到各种交互效果。而这些效果在平常翻看文章的时候碰到很多&#xff0c;但是一时半会又想不起来在哪&#xff0c;所以养成知识整理的习惯是很有必要的。这篇文章给大家推荐10个在 Web 开发中很有用的效果&#xff0c;记得收藏&#xff01; 超炫…

深入分析MFC文档视图结构(项目实践)

文档视图结构&#xff08;Document/View Architecture&#xff09;是MFC的精髓&#xff0c;也是Observer模式的具体实现框架之一&#xff0c;Document/View Architecture通过将数据和其表示分开&#xff0c;提供了很好的数据层次和表现层次的解耦。然而&#xff0c;虽然我们使用…

蓝图中实现人物移动2

从Pawn继承一个蓝图类并编写下面代码&#xff0c;并添加摄像机组件 1. 实现前后移动2. 实现左右移动3. 实现鼠标移动方向4. 实现鼠标俯仰

php 提取前一百个字,如何在PHP中提取字符串的前100個字符?

I am looking for a way to pull the first 100 characters from a string variable to put in another variable for printing.我正在尋找一種方法&#xff0c;從字符串變量中提取前100個字符&#xff0c;並將其放入另一個變量中進行打印。Is there a function that can do th…

实现两个pawn的切换

在playercontroller里面编写下面代码并把两个pawn放置到场景中

zoj2008 最短路

题意&#xff1a;给你n个点的有向图&#xff0c;从1点到其他所有点又从其他点回到1点的最短路。 思路&#xff1a;可以求一次从1点出发的最短路&#xff0c;再反向建图&#xff0c;再求一次从1出发的最短路&#xff0c;把两次的结果加起来就是题目所求。由于边比较多&#xff0…

steam程序员php玩的游戏,Steam:又一款烧脑的编程游戏上线,宅男回家了也要开心加班!...

原标题&#xff1a;Steam&#xff1a;又一款烧脑的编程游戏上线&#xff0c;宅男回家了也要开心加班&#xff01;要是小伙伴们喜欢什么解谜、编程类游戏&#xff0c;相信Steam上的《程序员升职记》应该都是绿了的游戏&#xff0c;这款给宅男们设计智力游戏能让你享受到从底层到…

模式(一)javascript设计模式

模式有三种&#xff1a;Architectural Pattern、Design Pattern、Coding Pattern&#xff0c;即&#xff1a;框架模式、设计模式、编程模式。本文主要讲解javascript中的设计模式&#xff0c;好的设计模式能够提高代码的重用性&#xff0c;可读性&#xff0c;使代码更容易的维护…

matlab如何提高运算速速,如何提高以下程序的运算速度及有选择性的保存数据?...

多谢管理员math的关注。“空位随机游走过程”有英语我也不知道如何说。只知道“空位”叫做&#xff1a;vacancy我解解释一下整个过程。不过过程比较长一些&#xff01;为了说明问题&#xff0c;我就举个例子如&#xff1a;Fe-Mg二元合金&#xff0c;其中Mg占3%&#xff0c;空位…