Android中 Handler使用全解

使用Handler的大致流程:

  1、首先创建一个Handler对象,可以直接使用Handler无参构造函数创建Handler对象,也可以继承Handler类,重写handleMessage方法来创建Handler对象。

  2、在监听器中,调用Handlerpost方法,将要执行的线程对象添加到线程队列当中。此时将会把该线程对象添加到handler对象的线程队列中。

  3、将要执行的操作写在线程对象的run方法中,一般是一个Runnable对象,复写其中的run方法就可以了。

  Handler包含了两个队列,其中一个是线程队列,另外一个是消息队列。使用post方法会将线程对象放到该handler的线程队列中,使用sendMessage(Message message)将消息放到消息队列中。

  如果想要这个流程一直执行的话,可以在run方法内部执行postDelayed或者post方法,再将该线程对象添加到消息队列中,重复执行。想要线程停止执行,调用Handler对象的removeCallbacks(Runnable r) 方法从线程队列中移除线程对象,使线程停止执行。

  HandlerAndroid 提供了一种异步消息处理机制,当向消息队列中发送消息 (sendMessage)后就立即返回,而从消息队列中读取消息时会阻塞,其中从消息队列中读取消息时会执行Handler中的public void handleMessage(Message msg) 方法,因此在创建Handler时应该使用匿名内部类重写该方法,在该方法中写上读取到消息后的操作,使用Handler的 obtainMessage() 来获得消息对象。

  Handler与线程的关系:

  使用Handlerpost方法将Runnable对象放到Handler的线程队列中后,该Runnable的执行其实并未单独开启线程,而是仍然在当前Activity线程中执行的,Handler只是调用了Runnable对象的run方法。

  Bundle是什么:

  Bundle是一个特殊的map,它是传递信息的工具,它的键只能是string类型,而且值也只能是常见的基本数据类型。

  如何让Handler执行Runnable时打开新的线程:

  1、首先生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能,这个类由Android应用程序 框架提供

  HandlerThread handlerThread = new HandlerThread("handler_thread");

  2、在使用HandlerThreadgetLooper()方法之前,必须先调用该类的start();

  handlerThread.start();

  3、根据这个HandlerThread对象得到其中的Looper对象。4、创建自定义的继承于Handler类的子类,其中实现一个参数为Looper对象的构造方法,方法内容调用父类的构造函数即可。

  5、使用第三步得到的Looper对象创建自定义的Handler子类的对象,再将消息(Message)发送到该Handler的消息队列中,Handler复写的handleMessage()将会执行来处理消息队列中的消息。

  消息,即Message对象,可以传递一些信息,可以使用arg1.arg2,Object传递一些整形或者对象,还可以使用Message对象的 setData(Bundle bundle)来讲Bundle对象传递给新创建的线程,新创建的线程在执行handleMessage(Message msg)时可以从message中利用getData()提取出Bundle对象来进行处理。

view sourceprint?

01 public class HandlerTest2 extends Activity { 
02     @Override 
03     protected void onCreate(Bundle savedInstanceState) { 
04      stub 
05         super.onCreate(savedInstanceState); 
06         setContentView(R.layout.main); 
07         //打印了当前线程的ID 
08         System.out.println("Activity-->" + Thread.currentThread().getId()); 
09         //生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能,这个类由Android应用程序框架提供 
10         HandlerThread handlerThread = new HandlerThread("handler_thread"); 

11         //在使用HandlerThreadgetLooper()方法之前,必须先调用该类的start(); 
12         handlerThread.start(); 
13         MyHandler myHandler = new MyHandler(handlerThread.getLooper()); 
14         Message msg = myHandler.obtainMessage(); 
15         //msg发送到目标对象,所谓的目标对象,就是生成该msg对象的handler对象 
16         Bundle b = new Bundle(); 

17         b.putInt("age", 20); 
18         b.putString("name", "Jhon"); 
19         msg.setData(b); 
20         msg.sendToTarget(); 
21     } 
22         class MyHandler extends Handler{ 
24         public MyHandler(){ 
25               
26         } 
27         public MyHandler(Looper looper){ 
28             super(looper); 

29         } 
30         @Override 
31         public void handleMessage(Message msg) { 
32             Bundle b = msg.getData(); 
33             int age = b.getInt("age"); 
34             String name = b.getString("name"); 
35             System.out.println("age is " + age + ", name is" + name); 
36             System.out.println("Handler--->" + Thread.currentThread().getId()); 
37             System.out.println("handlerMessage"); 
38         } 
39     } 
40 }

最新历史版本 :Android Handler详解 

Java代码

  /***

  * Handler的定义:

  主要接受子线程发送的数据并用此数据配合主线程更新UI。当应用程序启动时,

  * Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发比如说,

  你要是点击一个 Button ,Android会分发事件到Button上,来响应你的操作。

  如果此时需要一个耗时的操作,例如联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,

  如果你放在主线程中的话,界面会出现假死现象如果5秒钟还没有完成的话,会收到Android系统的一个错误提示 "强制关闭"

  这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,Android主线程是线程不安全的,

  也就是说,更新UI只能在主线程中更新,子线程中操作是危险的。这个时候,Handler就出现了,来解决这个复杂的问题 ,

  由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,

  这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象(里面包含数据),把这些消息放入主线程队列中,配合主线程进行更新UI

  * Handler一些特点:

  * Handler可以分发Message对象和Runnable对象到主线程中每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),

  它有两个作用: (1): 安排消息或Runnable 在某个主线程中某个地方执行, (2)安排一个动作在不同的线程中执行

  * Handler中分发消息的一些方法

  * post(Runnable)

  * postAtTime(Runnable,long)

  * postDelayed(Runnable,long)

  * sendEmptyMessage(int)

  * sendMessage(Message)

  * sendMessageAtTime(Message,long)

  * sendMessageDelayed(Message,long)

  以上post类方法允许你排列一个Runnable对象到主线程队列中,当需要在不同于主UI线程中执行则需要配合HandlerThread进行使用:

  * HandlerThread handlerThread = new HandlerThread("myHandlerThread");

  * handlerThread.start();

  * handler = new Handler(handlerThread.getLooper());* sendMessage类方法允许你安排一个带数据的Message对象到队列中,等待更新.

  * @author xiaoshuang

  *

  */

  public class HandlerActivity extends Activity {

  private TextView textView;

  private MyHandler myHandler;

  private Button button;

  private ProgressBar progressBar;

  private MyThread m=new MyThread();

  /** Called when the activity is first created. */

  @Override

  public void onCreate(Bundle savedInstanceState) {

  super.onCreate(savedInstanceState);

  setContentView(R.layout.main);

  textView=(TextView)findViewById(R.id.text);

  button=(Button)findViewById(R.id.startButton);

  progressBar=(ProgressBar)findViewById(R.id.bar);

  progressBar.setMax(100);

  button.setOnClickListener(new View.OnClickListener() {

  @Override

  public void onClick(View arg0) {

  myHandler=new MyHandler();

  new Thread(m).start();

  System.out.println("onCreate--The Thread is: "+Thread.currentThread().getId());

  }

  });

  }

  //在对UI进行更新时,执行时所在的线程为主UI线程

  class MyHandler extends Handler{//继承Handler类时,必须重写handleMessage方法

  public MyHandler(){

  }

  public MyHandler(Looper l){

  super(l);

  }

  @Override

  public void handleMessage(Message msg) {//执行接收到的通知,此时执行的顺序是按照队列进行,即先进先出

  System.out.println("Handler--The ThreadId is: "+Thread.currentThread().getId());

  super.handleMessage(msg);

  Bundle b=msg.getData();

  String textStr0=textView.getText().toString();

  String textStr1=b.getString("textStr");

  HandlerActivity.this.textView.setText(textStr0+" "+textStr1);//更改TextView中的值

  int barValue=b.getInt("barValue");HandlerActivity.this.progressBar.setProgress(barValue);//更改进度条当中的值

  }

  }

  //该线程将会在单独的线程中运行

  class MyThread implements Runnable{

  int i=1;

  @Override

  public void run() {

  while(i<11){

  System.out.println("Thread--The ThreadId is: "+Thread.currentThread().getId());

  try {

  Thread.sleep(1000);

  } catch (InterruptedException e) {

  e.printStackTrace();

  }

  Message msg=new Message();

  Bundle b=new Bundle();

  b.putString("textStr", "线程运行"+i+"");

  b.putInt("barValue", i*10);

  i++;

  msg.setData(b);

  HandlerActivity.this.myHandler.sendMessage(msg);//通过sendMessageHandler发送更新UI的消息

  }

  }

  }

  }

  /***


Android Handler 异步消息机制

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

Handler 常用方法:
post(Runnable)
        postAtTime(Runnable,long)
        postDelayed(Runnable long)
        sendEmptyMessage(int)
        sendMessage(Message)
        sendMessageAtTime(Message,long)
        sendMessageDelayed(Message,long)
以上post类方法允许你排列一个Runnable对象到主线程队列中,
        sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等待更新.


     个人认为Android 中Handler 很像 Web开发中的Ajax。拿jquery 的$.ajax()方法来举例:
$.ajax({
     url:"xxxx.jsp",
     dataType:"text",
     success:function(message){ // 处理返回的结果}
      })

首先我们按老规矩先看Demo的效果图:






1、点击 测试 按钮的开启一条线程处理其他比较耗时的业务,相当于 一个Web页面点击页面的某个按钮后调用javascript 的ajax方法去后台去数据,而本身的页面是没变的。

2、是否是异步的呢?从图二可以看出。先打印出了线程中 “start Thread”,才执行 onClick 方法中的 “OnClick........”

3、下面代码效果等于ajax请求的后台的响应,那Java来说就是 printWriter.prinlt(1);

  1. Thread thread = new Thread()
  2.     {
  3.             public void run()
  4.             {
  5.                     Log.i(TAG, "start Thread");
  6.                    
  7.                     //发送一个空消息到消息队列里面
  8.                     //此方法相当于后台往前台Ajax响应结果,在Java当中,相当于一个Action方法里面out.println(1);
  9.                     handler.sendEmptyMessage(1);
  10.             };
  11.     };
复制代码

4、 以下代码相当于ajax的 success:function(message){if(message==1){//do something}}
  1. if(msg.what ==1)
  2.                     {
  3.                             txtTest.setText("异步处理结果 === Handler ");
  4.                     }
复制代码


下面看一下具体代码是怎么实现的:

main.xml文件:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.     android:orientation="vertical"
  4.     android:layout_width="fill_parent"
  5.     android:layout_height="fill_parent"
  6.     >
  7. <TextView  
  8.         android:id="@+id/txtTest"
  9.     android:layout_width="fill_parent"
  10.     android:layout_height="wrap_content"
  11.     android:text="HandlerTest"
  12.     />
  13.    
  14.    
  15.    <Button android:id="@+id/btnTest"  
  16.            android:layout_width="fill_parent"
  17.     android:layout_height="wrap_content"
  18.     android:text="测试"
  19.     />
  20. </LinearLayout>
复制代码

Activity:
  1. package com.droidstouc.handler.test;

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

  10. /**
  11. * Android Handler 异步消息处理机制
  12. * @author Administrator
  13. *
  14. */
  15. public class HandlerTestActivity extends Activity {
  16.    
  17.        
  18.        
  19.         private static final String TAG="HandlerTestActivity";
  20.        
  21.         private Button btnTest;
  22.         private TextView  txtTest;
  23.        
  24.        
  25.     public void onCreate(Bundle savedInstanceState) {
  26.         super.onCreate(savedInstanceState);
  27.         setContentView(R.layout.main);
  28.         
  29.         
  30.         txtTest = (TextView) this.findViewById(R.id.txtTest);
  31.         btnTest= (Button) this.findViewById(R.id.btnTest);
  32.         
  33.         //设置 OnClick **       
  34.         btnTest.setOnClickListener(new BtnTestOnClickListener());
  35.     }
  36.    
  37.    
  38.    
  39.     //点击测试按钮后调用 BtnTestOnClickListener 的 OnClick 方法
  40.     class BtnTestOnClickListener implements OnClickListener
  41.     {
  42.                 @Override
  43.                 public void onClick(View v)
  44.                 {
  45.                 /*        //把线程对象放到handler的队列中,线程会马上启动执行
  46.                         handler.post(thread);*/
  47.                        
  48.                         //启动线程
  49.                         thread.start();
  50.                         try
  51.                         {
  52.                                 // 为了看到异步效果,我让当前线程停止了2秒钟
  53.                                 Thread.sleep(2000);
  54.                         }
  55.                         catch (InterruptedException e)
  56.                         {
  57.                                 e.printStackTrace();
  58.                         }
  59.                        
  60.                         Log.i(TAG, "OnClick........");
  61.                 }
  62.            
  63.     }
  64.    
  65.    
  66.    // 定义一个Handler,用来异步处理数据
  67.     Handler handler = new Handler()
  68.     {
  69.             //相当于jquery $.ajax方法中的 Success:function(){}
  70.            
  71.             public void handleMessage(android.os.Message msg)
  72.             {
  73.                     // 对线程中 handler 返回的结果进行处理
  74.                    
  75.                     Log.i(TAG, "结果返回,正在处理");
  76.                     if(msg.what ==1)
  77.                     {
  78.                             txtTest.setText("异步处理结果 === Handler ");
  79.                     }
  80.                    
  81.             };
  82.     };
  83.    
  84.    
  85.    
  86.     Thread thread = new Thread()
  87.     {
  88.             public void run()
  89.             {
  90.                     Log.i(TAG, "start Thread");
  91.                    
  92.                     //发送一个空消息到消息队列里面
  93.                     //此方法相当于后台往前台Ajax响应结果,在Java当中,相当于一个Action方法里面out.println(1);
  94.                     handler.sendEmptyMessage(1);
  95.             };
  96.     };
  97. }

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值