Android:Handler实现异步处理功能

一.一个问题

有这样一个问题值得我们思考,若把一些类似于下载的功能(既耗时且不一定有结果)写在Activity(主线程)里,会导致Activity阻塞,长时间无响应,直至页面假死(如果5秒钟还没有完成的话,会收到Android系统的一个错误提示 "强制关闭")。因此,我们需要把这些耗时的操作放在单独的子线程中操作。这就是Handler的使命。Handler提供异步处理的功能,发送和接收不是同时的(Activity的主线程和线程队列里的线程是不同的线程,并行进行,互不影响)。

二.Handler简介

Handler 为Android操作系统中的线程通信工具,它主要由两个作用:(1)安排消息或Runnable 在某个主线程中某个地方执行(2)安排一个动作在另外的线程中执行。每个Handler对象维护两个队列(FIFO),消息队列和Runnable队列, 都是有Android操作系统提供的。Handler可以通过这两个队列来分别:

  1. 发送、接受、处理消息–消息队列;
  2. 启动、结束、休眠线程–Runnable队列;

Handler的使用方法大体分为3个步骤:1.创建Handler对象。2.创建Runnable和消息。3.调用post以及sendMessage方法将Runnable和消息添加到队列。

三.Runnable队列

1.java中的线程

在java中,线程的创建有两种方法:继承Thread类和实现Runnable接口。而这最重要的都是要复写run方法来实现线程的功能。当线程的时间片到了,开始运行时,就执行run()函数,执行完毕,就进入死亡状态。

举个创建线程的例子:

Runnable r=new Runnable(){ 

@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("thread");
handler.postDelayed(thread, 3000);
}
};

  

2.关于Runnable队列

(1)原理

Android的线程异步处理机制:Handler对象维护一个线程队列,有新的Runnable送来(post())的时候,把它放在队尾,而处理 Runnable的时候,从队头取出Runnable执行。当向队列发送一个Runnable后,立即就返回,并不理会Runnable是否被执行,执行 是否成功等。而具体的执行则是当排队排到该Runnable后系统拿来执行的。这就好比邮局的例子。寄信者将信写好后放入邮筒就回家了,他并不知道邮件何 时被邮局分发,何时寄到,对方怎样读取这些事。这样,就实现了Android的异步处理机制。

(2)具体操作

向队列添加线程:

handler.post(Runnable );将Runnable直接添加入队列

handler.postDelayed(Runnable, long)延迟一定时间后,将Runnable添加入队列

handler.postAtTime(Runnable,long)定时将Runnable添加入队列

终止线程:

handler.removeCallbacks(thread);将Runnable从Runnable队列中取出

四.消息队列

1.消息对象

(1)Message对象

Message对象携带数据,通常它用arg1,arg2来传递消息,当然它还可以有obj参数,可以携带Bundle数据。它的特点是系统性能消耗非常少。

初始化: Message msg=handler.obtainMessage();

(2)Bundle对象

Bundle是Android提供的类,可以把它看做是特殊的Map,即键值对的包。而它特殊在键和值都必须要是基本数据类型或是基本数据类型的数组(Map的键值要求都是对象),特别的,键要求都是String类型。用Message来携带Bundle数据:

放入:msg.setData(Bundle bundle);

取出:msg.getData();

2.关于消息队列

(1)原理

Android的消息异步处理机制:Handler对象维护一个消息队列,有新的消息送来(sendMessage())的时候,把它放在队尾,之后排队 到处理该消息的时候,由主线程的Handler对象处理(handleMessage())。整个过程也是异步的,和Runnable队列的原理相同。

(2)具体操作:

向队列添加Runnable:handler.sendMessage(Message);

将消息发送到消息队列msg.sendToTarget();

延迟一定时间后,将消息发送到消息队列 handler.sendMessageDelayed(Message,long);

定时将消息发送到消息队列 handler.sendMessageAtTime(Message,long)

处理消息:

消息的具体处理过程,需要在new Handler对象时使用匿名内部类重写Handler的handleMessage(Message msg)方法,如下:

Handler handler=new Handler(){ 

@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
。。。。。。 

。。。。。。
}
};

  

五.Handler的两个作用

1.安排消息或Runnable 在某个主线程中某个地方执行

代码示例:

public class HandlerTestActivity extends Activity {
private Button start;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.handlertest);
start=(Button) findViewById(R.id.start);
start.setOnClickListener(new startListener()); 

System.out.println("Activity Thread:"+Thread.currentThread().getId());
}
Handler handler=new Handler();
Runnable thread=new Runnable(){ 

@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("HandlerThread:"+Thread.currentThread().getId()); 

}
};
class startListener implements OnClickListener{ 

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
handler.post(thread);
}
} 

} 

这个小程序中,首先程序启动,进入onCreate(),打印出当前线程(即主线程)的ID,之后点击按钮start,会将线程thread添加到线程队 列,执行线程thread,thread的作用就是打印出当前线程的ID。在这个程序中,我们可以看到通过Handler我们可以实现安排 Runnable 在某个主线程中某个地方执行,即作用(1)。

不过这里有个小小的陷阱,你发现了吗?这个程序看上去似乎实现了Handler的异步机制, handler.post(thread)似乎实现了新启线程的作用,不过通过执行我们发现,两个线程的ID相同!也就是说,实际上thread还是原来 的主线程,由此可见,handler.post()方法并未真正新建线程,只是在原线程上执行而已,我们并未实现异步机制。

2.安排一个动作在另外的线程中执行。

(1)java中标准的创建线程的方法

第一步:

 Runnable r=new Runnable(){ 

@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("thread");
handler.postDelayed(thread, 3000);
}
}; 

第二步:

Thread t=new Thread (r);

第三步:

t.start();

若把上面示例程序中的handler.post(thread);语句改成以上形式,通过打印我们可以看到,两个ID是不同的,新的线程启动了!

(2)关于Looper

Looper类用来为线程开启一个消息循环,作用是可以循环的从消息队列读取消息,所以Looper实际上就是消息队列+消息循环的封装。每个线程只能对应一个Looper,除主线程外,Android中的线程默认是没有开启Looper的。

通过Handler与Looper交互,Handler可以看做是Looper的接口,用来向指定的Looper发送消息以及定义处理方法。默认情况下Handler会与其所在线程的Looper绑定,即:

Handler handler=new Handler();等价于Handler handler=new Handler(Looper.myLooper());

Looper有两个主要方法:

Looper.prepare();启用Looper
Looper.loop(); 让Looper开始工作,从消息队列里取消息,处理消息。

注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。

(3)Handler异步机制的实现

Handler是通过HandlerThread 使得子线程与主线程分属不同线程的。实际上,HandlerThread 是一个特殊的线程,它是一个封装好Looper的线程,

代码示例:

//创建一个名叫handler_hread的HandlerThread 对象
HandlerThread handlerThread=new HandlerThread("handler_hread"); 

//开启handlerThread,在使用handlerThread.getLooper()之前必须先调用start方法,否则取出的是空
handlerThread.start(); 

//将handler绑定在handlerThread的Looper上,即这个handler是运行在handlerThread线程中的
myHandler handler=new myHandler(handlerThread.getLooper()); 

class myHandler extends Handler{
public myHandler(){}
public myHandler(Looper looper){
super(looper);
}
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
System.out.println("Activity Thread:"+Thread.currentThread().getId());
}
} 

这样,就实现了handler的异步处理机制,在调用handler.post()方法,通过打印线程ID可以得知,子线程与主线程是分属不同线程的。

时间: 2024-10-01 19:08:32

Android:Handler实现异步处理功能的相关文章

Android:用Handler实现异步处理功能

Android:用Handler实现异步处理功能 - 51CTO.COM 一.一个问题 有这样一个问题值得我们思考,若把一些类似于下载的功能(既耗时且不一定有结果)写在Activity(主线程)里,会导致Activity阻塞,长时间无响应,直至页面假死(如果5秒钟还没有完成的话,会收到Android系统的一个错误提示 "强制关闭").因此,我们需要把这些耗时的操作放在单独的子线程中操作.这就是Handler的使命.Handler提供异步处理的功能,发送和接收不是同时的(Activity

Android Handler 异步消息处理机制的妙用 创建强大的图片加载类

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38476887 ,本文出自[张鸿洋的博客] 最近创建了一个群,方便大家交流,群号:55032675 上一篇博客介绍了Android异步消息处理机制,如果你还不了解,可以看:Android 异步消息处理机制 让你深入理解 Looper.Handler.Message三者关系 .那篇博客的最后,提出可以把异步消息处理机制不仅仅是在MainActivity中更新UI,可以用到别的地方,

Android开发之异步具体解释(一)Thread+Handler

请尊重他人的劳动成果,转载请注明出处:  Android开发之异步具体解释(一)Thread+Handler http://blog.csdn.net/fengyuzhengfan/article/details/40211589 在Android实际开发project中常常会进行一些诸如:文件读写.訪问网络等耗时的操作,这些耗时的操作是不建议放到UI线程里的. 所以我们会新开一个线程.在子线程中进行这些耗时的操作.耗时操作过程中.UI常常须要更新,但Android是不同意在子线程中改动UI的.

Android开发之异步详解(一)Thread+Handler

请尊重他人的劳动成果,转载请注明出处:  Android开发之异步详解(一)Thread+Handler http://blog.csdn.net/fengyuzhengfan/article/details/40211589 在Android实际开发工程中经常会进行一些诸如:文件读写.访问网络等耗时的操作,这些耗时的操作是不建议放到UI线程里的.所以我们会新开一个线程,在子线程中进行这些耗时的操作,耗时操作过程中,UI经常需要更新,但Android是不允许在子线程中修改UI的.所以就出现了Th

Android ------ handler 异步处理消息

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

Android开发之异步消息处理机制Handler

Android中的异步消息处理主要有四个部分组成,Message, Handler, MessageQueue和 Looper. 1.Message. 在线程之间传递的消息,可以内部携带少量的信息,用于在不同线程之间交换数据.可以使用what字段,arg1和arg2携带一些整型数据,obj字段携带一个object对象. 2.Handler. Handler,处理者的意思,它主要用于发送和处理消息的.发送消息一般使用Handler的sendMessage()方法,而发出的消息经过一系列地辗转处理后

Android线程之异步消息处理机制(二)——Message、Handler、MessageQueue和Looper

异步消息处理机制解析 Android中的异步消息处理主要有四个部分组成,Message.Handler.MessageQueue和Looper. 1.Message Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据.上个例子中就使用了Message的what字段,除此之外还可以使用arg1和arg2字段来携带一些整形数据,使用obj字段携带一个Object对象. 2.Handler Handler顾名思义也就是处理者的意思,它主要是用于发送和处理消息的

Android开发之异步详解(二)之AsyncTask

请尊重他人的劳动成果,转载请注明出处:Android开发之异步详解(二)之AsyncTask http://blog.csdn.net/fengyuzhengfan/article/details/40212745 我曾在<Android开发之异步详解(一)之Thread+Handler>一文中介绍过通过Thread+Handler实现异步操作.感兴趣的朋友可以看一下. 虽然Thread+Handler可以实现更新主线程的UI并实现异步,但Thread+Handler模式需要为每一个任务创建一

Android之ListView异步加载图片且仅显示可见子项中的图片

折腾了好多天,遇到 N 多让人崩溃无语的问题,不过今天终于有些收获了,这是实验的第一版,有些混乱,下一步进行改造细分,先把代码记录在这儿吧. 网上查了很多资料,发现都千篇一律,抄来抄去,很多细节和完整实例都没看到,只有自己一点点研究了,总体感觉 android 下面要显示个图片真不容易啊. 项目主要实现的功能: 异步加载图片图片内存缓存.异步磁盘文件缓存解决使用 viewHolder 后出现的图片错位问题优化列表滚动性能,仅显示可见子项中的图片无需固定图片显示高度,对高度进行缓存使列表滚动时不会