Android Handler介绍

/***

  * 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对象到队列中,等待更新.


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);//通过sendMessage向Handler发送更新UI的消息

  }

  }

  }

  }

 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的代码: 


package eoe.demo; 

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:一个应用程序中有一个进度条和一个按钮,当点击按钮后,每隔一秒钟进度条前进一部分。

 开发步骤: 
        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) 将要执行的线程对象放入到队列当中 


package eoe.demo; 

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); 
} 
} 
}; 
} 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值