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的使用

  • 2011年07月01日 19:35
  • 78KB
  • 下载

Android使用Handler实现子线程与子线程、主线程之间通信

今天这篇文章只讲一下怎么使用Handler实现子线程与子线程之间、子线程与主线程之间如何进行通信,关于具体的内部实现因为我也没研究过,所以这篇文章讲不了。一、子线程向主线程传值:这个实现比较简单,因为...

Android的Handler使用方法总结

  • 2013年08月15日 00:21
  • 4KB
  • 下载

Android review handler的使用

  • 2014年08月21日 20:10
  • 1.29MB
  • 下载

Android中使用Handler造成内存泄露的分析和解决

原文地址:http://www.linuxidc.com/Linux/2013-12/94065.htm 什么是内存泄露? Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟...

Android 多线程:使用Thread和Handler

  • 2014年08月18日 14:27
  • 22KB
  • 下载

android中Handler的使用方法和总结

  • 2011年11月12日 16:15
  • 135KB
  • 下载

Android中有关Handler的使用(二)

Android中有关Handler的使用(二)2、sendMessage版本的Handler的使用     这里介绍几种模型:a、默认的Handler(消息处理队列挂在主线程上)package com...

android中handler的使用

  • 2011年09月29日 12:54
  • 46KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android Handler的使用
举报原因:
原因补充:

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