异步消息处理 handler

当我们在处理下载或是其他需要长时间执行的任务时,如果直接把处理函数放Activity的OnCreate或是OnStart中,会导致执行过程中整个Activity无响应,如果时间过长,程序还会挂掉。Handler就是把这些功能放到一个单独的线程里执行,与Activity互不影响。因此我们需要另外起动一个线程来处理长耗时操作,而主线程则不受其影响,在耗时操作完结发送消息给主线程,主线程再做相应处理。那么线程之间的消息传递和异步处理用的就是Handler。

Andrioid中费时的操作要放在子线程中处理,更新UI要放在主线程中进行。如果根据子线程的动作或进度要更新UI,在子线程中进行是不安全的,这时需要用到handler。Handler运行在主线程(UI线程)中,与子线程通过Message对象来传递数据。Handler接收子线程传过来的Message对象(子线程通过sendMessage()方法传递),把这些消息放入主线程队列中,配合主线程更新UI。

Handler的作用:安排消息或Runnable在某个主线程中的某个地方执行;安排一个动作在不同的线程中执行。

例1: 一个应用程序中有2个按钮(start、end),当点击start按钮时,执行一个线程,这个线程在控制台输出一串字符串,并且每隔3秒再执行一次线程,直到点击end按钮为止,线程停止。

步骤为:

1、 在Activity中,创建一个Handler对象

Handler handler = new Handler();

2、 在Activity中,创建一个Runnable对象

a) 以匿名内部类的方式

b) 将要执行的操作写在Runnable对象中的run()方法中

i. 打印出一句话

ii. 调用Runnable对象的postDelayed()方法

Runnable updateThread = new Runnable(){ //将要执行的操作写在线程对象的run方法当中 public void run(){ System.out.println("updateThread"); //调用Handler的postDelayed()方法 ,将要执行的线程对象放入到队列当中,待时间结束后,运行制定的线程对象 handler.postDelayed(updateThread, 3000); } };

 
             

3、 在Activity中,编写start按钮需要的监听器,并绑定

a) 在这个监听器的Onclick()方法中,调用Handler的post()方法,将要执行的线程对象放到队列当中。

handler.post(updateThread);

4、 在Activity中,编写end按钮需要的监听器,并帮定

a) 在这个监听器的Onclick()方法中,调用Handler的removeCallbacks ()方法,删除队列当中未执行的线程对象。

handler.removeCallbacks(updateThread);

例2:一个应用程序中有一个进度条和一个按钮,当点击按钮后,每隔一秒钟进度条前进一部分.

步骤为:

1、 创建线程对象,通过匿名内部类的方式进行声明。

i. 声明一个变量用来设置进度条的进度

ii. 重写线程类的run方法(),里面编写要执行的操作

a. 打印一个字符串;

b. 进度条的值增加;

c. 得到一个消息对象;

d. 设置消息对象arg1的值;

e. 让线程休眠一秒钟;

f. 将消息对象放入到消息队列中;

g. 判断,如果进度条的值等于100,则将线程对象从队列中移除。

Runnable updateThread = new Runnable(){ //将要执行的操作写在线程对象的run方法当中 public void run(){ System.out.println("updateThread"); //调用Handler的postDelayed()方法 ,将要执行的线程对象放入到队列当中,待时间结束后,运行制定的线程对象 handler.postDelayed(updateThread, 3000); } };

2、使用匿名内部类的方法生成Handler对象,重写Handler对象的handlerMessage(Message msg)方法。

i. 这个方法传入了一个Message对象,即消息对象,首先设置进度条的进度(这个值是Messag对象里面的一个成员变量arg1);

ii. 将要执行的线程对象放入到队列当中。

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

注意: 使用Handler对象的post方法家在Runnable对象时不会新建线程,只是在当前线程中执行run方法。若要创建新的线程,需要使用Thread,将runnable对象作为参数传入。

Thread t = new Thread(r);

t.start();

为了使Activity和复杂的数据处理位于不同的线程中,可以使用HandlerThread,实现使用Looper来处理消息队列的功能,注意使用HandlerThread对象的getLooper方法之前,必须先调用该类的start方法。Looper在线程中运行一个消息循环,HandlerThread使用一个消息循环启用一个线程,而Handler用于处理消息。

Android中每一个Thread都跟着一个Looper,Looper可以帮助Thread维护一个消息队列,但是Looper和Handler没有什么关系。Android还提供了一个Thread继承类HanderThread可以帮助我们处理,在HandlerThread对象中可以通过getLooper方法获取一个Looper对象控制句柄,我们可以将其这个Looper对象映射到一个Handler中去来实现一个线程同步机制。

Messge对象的sendToTarget方法是将message发送到目标对象,所谓的目标对象就是生成改messgae对象的handler对象。

HandlerThread handlerThread = new HandlerThread("handlerThread");//生成handlerThread对象 handlerThread.start();//启动handlerThread对象 MyHandler myhandler = new MyHandler(handlerThread.getLooper());//使用handlerThread对象的looper对象作为参数,生成Myhandler对象(Handler的子类)。 Message msg = myhandler.obtainMessage(); msg.arg1 = 1; msg.sendToTarget(); class MyHandler extends Handler{ public MyHandler(){ } //编写以Looper对象为参数的构造函数 public MyHandler(Looper looper){ super(looper); } @Override //重写handleMessage方法 public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); System.out,println(msg.arg1); System.out.println("MyHandler---> id: " + Thread.currentThread().getId()); System.out.println("MyHandler---> name: " + Thread.currentThread().getName()); } }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值