Android Handler的使用

转载 2012年03月28日 14:21:32

转自:http://www.eoeandroid.com/thread-72298-1-1.html

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 eoe.demo; 

  2. import android.app.Activity; 
  3. import android.os.Bundle; 
  4. import android.os.Handler; 
  5. import android.view.View; 
  6. import android.view.View.OnClickListener; 
  7. import android.widget.Button; 

  8. public class HandlerTest extends Activity { 
  9. /** Called when the activity is first created. */ 
  10. private Button startButton; 
  11. private Button endButton; 

  12. @Override 
  13. public void onCreate(Bundle savedInstanceState) { 
  14. super.onCreate(savedInstanceState); 
  15. setContentView(R.layout.main); 
  16. //根据id获得控件对象 
  17. startButton = (Button)findViewById(R.id.startButton); 
  18. endButton = (Button)findViewById(R.id.endButton); 
  19. //为控件设置监听器 
  20. startButton.setOnClickListener(new StartButtonListener()); 
  21. endButton.setOnClickListener(new EndButtonListener()); 


  22. class StartButtonListener implements OnClickListener{ 
  23. public void onClick(View v) { 
  24. //调用Handler的post()方法,将要执行的线程对象放到队列当中 
  25. handler.post(updateThread); 



  26. class EndButtonListener implements OnClickListener{ 
  27. public void onClick(View v) { 
  28. //调用Handler的removeCallbacks()方法,删除队列当中未执行的线程对象 
  29. handler.removeCallbacks(updateThread); 




  30. //创建Handler对象 
  31. Handler handler = new Handler(); 
  32. //新建一个线程对象 
  33. Runnable updateThread = new Runnable(){ 
  34. //将要执行的操作写在线程对象的run方法当中 
  35. public void run(){ 
  36. System.out.println("updateThread"); 
  37. //调用Handler的postDelayed()方法 
  38. //这个方法的作用是:将要执行的线程对象放入到队列当中,待时间结束后,运行制定的线程对象 
  39. //第一个参数是Runnable类型:将要执行的线程对象 
  40. //第二个参数是long类型:延迟的时间,以毫秒为单位 
  41. handler.postDelayed(updateThread, 3000); 

  42. }; 
  43. }
复制代码

       上面是一个最简单的例子,下面再看另外一个例子。 
       示例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) 将要执行的线程对象放入到队列当中 

Java代码:

  1. package eoe.demo; 

  2. import android.app.Activity; 
  3. import android.os.Bundle; 
  4. import android.os.Handler; 
  5. import android.os.Message; 
  6. import android.view.View; 
  7. import android.view.View.OnClickListener; 
  8. import android.widget.Button; 
  9. import android.widget.ProgressBar; 

  10. public class ProgressBarHandlerTest extends Activity { 
  11. /** Called when the activity is first created. */ 

  12. private ProgressBar progressBar; 
  13. private Button startButton; 

  14. @Override 
  15. public void onCreate(Bundle savedInstanceState) { 
  16. super.onCreate(savedInstanceState); 
  17. setContentView(R.layout.main); 

  18. progressBar = (ProgressBar)findViewById(R.id.progressbar); 
  19. startButton = (Button)findViewById(R.id.startButton); 

  20. startButton.setOnClickListener(new ProgressBarOnClickListener()); 


  21. class ProgressBarOnClickListener implements OnClickListener{ 
  22. public void onClick(View v) { 
  23. //设置进度条为可见状态 
  24. progressBar.setVisibility(View.VISIBLE); 
  25. updateBarHandler.post(updateThread); 



  26. //使用匿名内部类来复写Handler当中的handlerMessage()方法 
  27. Handler updateBarHandler = new Handler(){ 
  28. @Override 
  29. public void handleMessage(Message msg) { 
  30. progressBar.setProgress(msg.arg1); 
  31. updateBarHandler.post(updateThread); //将要执行的线程放入到队列当中 

  32. }; 

  33. //线程类,该类使用匿名内部类的方式进行声明 
  34. Runnable updateThread = new Runnable(){ 
  35. int i = 0; 
  36. public void run() { 
  37. // TODO Auto-generated method stub 
  38. System.out.println("Begin Thread"); 
  39. i+=10; 
  40. //得到一个消息对象,Message类是android系统提供的 
  41. Message msg = updateBarHandler.obtainMessage(); 
  42. //将Message对象的arg1参数的值设置为i 
  43. msg.arg1 = i; //用arg1、arg2这两个成员变量传递消息,优点是系统性能消耗较少 
  44. try{ 
  45. Thread.sleep(1000); //让当前线程休眠1000毫秒 
  46. }catch(InterruptedException ex){ 
  47. ex.printStackTrace(); 

  48. //将Message对象加入到消息队列当中 
  49. updateBarHandler.sendMessage(msg); 
  50. //如果i的值等于100 
  51. if (i == 100){ 
  52. //将线程对象从队列中移除 
  53. updateBarHandler.removeCallbacks(updateThread); 


  54. }; 
  55. }
复制代码
 一、 Handler与线程的关系 

       Handler在默认情况下,实际上它和调用它的Activity是处于同一个线程的。 
例如在Handler的使用(一)的示例1中,虽然声明了线程对象,但是在实际调用当中它并没有调用线程的start()方法,而是直接调用当前线程的run()方法。 

       通过一个例子来证实一下 

       示例1:一个Android应用程序,在Activity中创建Handler和线程对象,并且在Activity的onCreate()方法中输出当前线程的id和名字,然后在线程对象的run方法中也打印输出下当前线程的id和名字。如果说,Activity输出的结果与线程对象输出的结果是一样的,那么就表示它们使用的是同一个线程。 
下面是Activity代码: 

Java代码:
  1. package eoe.demo; 

  2. import android.app.Activity; 
  3. import android.os.Bundle; 
  4. import android.os.Handler; 

  5. public class HandlerTwo extends Activity { 
  6. /** Called when the activity is first created. */ 

  7. Handler handler = new Handler(); 

  8. @Override 
  9. public void onCreate(Bundle savedInstanceState) { 
  10. super.onCreate(savedInstanceState); 
  11. //在设置布局文件之前先调用post方法, 
  12. //表示在执行完线程之后才会显示布局文件中的内容,而线程中又设置了休眠10秒钟, 
  13. //所以最终效果为,先显示应用程序主界面,等待10秒钟之后才显示布局文件中的内容 
  14. handler.post(r); 
  15. setContentView(R.layout.main); 
  16. System.out.println("activity id--->"+Thread.currentThread().getId()); 
  17. System.out.println("activity name--->"+Thread.currentThread().getName()); 


  18. Runnable r = new Runnable(){ 

  19. public void run() { 
  20. //输出当前线程的id和name 
  21. //如果这里输出的线程id、name与上面onCreate()方法中输出的线程id、name相同的话, 
  22. //那么则表示,他们使用的是同一个线程 
  23. System.out.println("runnable_id--->"+Thread.currentThread().getId()); 
  24. System.out.println("runnable_name--->"+Thread.currentThread().getName()); 
  25. try{ 
  26. Thread.sleep(10000); //让线程休眠10秒 
  27. }catch(InterruptedException e){ 
  28. e.printStackTrace(); 


  29. }; 
  30. }
复制代码

下图是执行的结果: 


       根据结果可以看出,两个输出的id和name都相同,它们使用的是同一个线程。 

       现在将Activity中的代码修改一下,新建一个线程Thread,然后调用线程的start()方法,再观察一下控制台的输出结果。 

       这里只要将上面的代码稍微修改一下就可以了 
       1、先将handler.post(r)注释掉 
       2、再添加下面两句代码就OK了 

Java代码:

  1. //handler.post(r); 
  2. Thread t = new Thread(r); 
  3. t.start();
复制代码

输出结果: 


       从这个输出结果中可以看出,这次线程对象的id、name与activity里的线程id、name完全不一样了,由此可见,它们现在使用的不是同一个线程。 

       这个例子中还掩饰了一个效果,就是平时我们是将Handler的post()方法放在setContentView(R.layout.main)这个方法之后调用,将设置完布局之后再执行其他的操作,而在这个例子中,是将Handler的post()方法放在setContent()方法之前调用,而post里传递的线程对象的run()方法呢,又执行了休眠线程10秒钟,所以运行实现的效果会是,当程序运行后,首先Activity上没有任何内容,过来10秒之后,才会显示Activity里的内容。 

       二、 Bundle和如何在新线程中处理消息 
       首先介绍一下Bundle:
 
       Bundle它是一个以string为键,可以由其他数据类型作为值的一个mapping,相当于把数据当成一个包。在初学的阶段可以将它当成特殊的一个HashMap对象,不过HashMap的键和值都是Object类型的,而Bundle的键却是String类型。 

       通过一个例子来使用一下Bundle和如何在新线程中处理消息 
       示例2:一个Android应用程序,先打印Activity当前使用的线程id,然后再创建一个新线程,使用Bundl存储值,最后打印出线程的id和Bundle中存储的值。 
看一下输出结果: 



Android中的Handler使用方式

对Android中的Handler的使用方式和其内部的一些机制进行简单的总结
  • jinhuoxingkong
  • jinhuoxingkong
  • 2017年03月14日 15:57
  • 460

Android中Handler的使用

Handler是Android中引入的一种让开发者参与处理线程中消息循环的机制。每个Hanlder都关联了一个线程,每个线程内部都维护了一个消息队列MessageQueue,这样Handler实际上也...
  • sunqunsunqun
  • sunqunsunqun
  • 2015年07月29日 00:16
  • 36736

Android中Handler使用实例

本文通过“使用新线程计算质数”这样一个demo,简单讲解如何在Android中使用Handler进行多线程开发。 为了更好地理解Handler的工作原理,先介绍一下Handler一起工作的几个组件。...
  • jasper_success
  • jasper_success
  • 2016年02月16日 16:37
  • 1924

Android Handler正确使用姿势

Android Handler正确使用姿势
  • geanwen
  • geanwen
  • 2017年01月08日 15:14
  • 1601

Android Handler使用详解

handler是android给我们提供用来更新UI的一套机制,也是一套消息处理的机制,我们可以发送消息,也可以通过它处理消息。它最根本的目的就是解决多线程并发问题,假设如果在一个Activity当中...
  • c19344881x
  • c19344881x
  • 2015年01月07日 17:02
  • 1587

Android Studio——android中handler用法总结

原文链接:http://blog.sina.com.cn/s/blog_77c6324101016jp8.html 一、Handler的定义:     Handler主要接收子...
  • oscar92420aaa
  • oscar92420aaa
  • 2016年01月15日 15:50
  • 3419

Android之Handler简单用法

今天給大家带来的是Androidzh
  • Joker_Ya
  • Joker_Ya
  • 2014年10月22日 20:09
  • 6296

Android中handler的使用及原理---学习笔记

Android中UI操作是线程不安全的操作,如果有多个线程并发操作UI组件,就会出现线程安全问题,所以Android中制定了一个规则:在Android中只允许主线程(UI线程)修改Activity中的...
  • u013991521
  • u013991521
  • 2015年07月19日 10:33
  • 4331

Android中handler的用法实例

Android中handler的用法实例 Handler主要用于不同线程之间的通信,尤其是普通线程通过handler机制发送message给主线程(UI线程)来更新UI,或者是把耗时的操作发送给ser...
  • zero9988
  • zero9988
  • 2015年12月04日 20:07
  • 1754

Android中的Handler的机制与用法详解

目录结构 Android中的Handler的机制与用法详解,什么是Handler,如何传递 Message,传递 Runnable 对象,传递 Callback 对象,Handler 原理是什么...
  • wangning13ji
  • wangning13ji
  • 2016年08月23日 11:43
  • 1453
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android Handler的使用
举报原因:
原因补充:

(最多只允许输入30个字)