`
zengyan2012
  • 浏览: 413786 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

android 多线程 AsyncTask handler

阅读更多

 

 

转自: http://www.moandroid.com/?p=1563

========================================================================

 

在前面的关于Java I/O的学习中,有一个我们需要牢记的是:对数据流的操作都是阻塞的,在一般情况下,我们是不需要考虑这个问题的,但是在Android 实现联网的时候,我们必须考虑到这个问题。比如:从网络上下载一张图片:
public Bitmap returnBitmap(String url)
{
URL myFileUrl = null;
Bitmap bitmap = null;
try{
myFileUrl = new URL(url);
}catch(MalformedURLException e){
e.printStackTrace();
return null;
};
try{
HttpURLConnection conn = (HttpURLConnection)myFileUrl.openConnection();
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
bitmap = BitmapFactroy.decodeStream(is);
is.close();
}catch(IOException e){
e.printStackTrace();
}
return bitmap;
}
由于网络连接需要很长的时间,需要3-5秒,甚至更长的时间才能返回页面的内容。如果此连接动作直接在主线程,也就是UI线程中处理,会发生什么情况呢?整个程序处于等待状态,界面似乎是“死”掉了。为了解决这个问题,必须把这个任务放置到单独线程中运行,避免阻塞UI线程,这样就不会对主线程有任何影响。举个例子如下:
private void connect(String strURL){
new Thread() {
public void run() {
try {
HttpClient client = new DefaultHttpClient();
// params[0]代表连接的url
HttpGet get = new HttpGet(url.getText().toString());
HttpResponse response = client.execute(get);
HttpEntity entity = response.getEntity();
long length = entity.getContentLength();
InputStream is = entity.getContent();
String s = null;
if (is != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[128];
int ch = -1;
int count = 0;
while ((ch = is.read(buf)) != -1) {
baos.write(buf, 0, ch);
count += ch;
}
s = new String(baos.toByteArray());
Log.V(“moandroid sample”,s);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}

使用Handler更新界面

如何将下载的信息显示在界面上了,比如说下载的进度。Android SDK平台只允许在主线程中调用相关View的方法来更新界面。如果返回结果在新线程中获得,那么必须借助Handler来更新界面。为此,在界面Activity中创建一个Handler对象,并在handleMessage()中更新UI。
//Task在另外的线程执行,不能直接在Task中更新UI,因此创建了Handler
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
String m = (String) msg.obj;
message.setText(m);
}
};
只需要将上面的
Log.V(“moandroid sample”,s);
替换为:
s = new String(baos.toByteArray());
Message mg = Message.obtain();
mg.obj = s;
handler.sendMessage(mg);

AsyncTask

看上去修改后的connect()方法已经可用了,但是这种匿名程的方式是存在缺陷的:

  • 线程的开销较大,如果每个任务都要创建一个线程,那么应用程 序的效率要低很多;
  • 线程无法管理,匿名线程创建并启动后就不受程序的控制了,如果有很多个请求发送,那么就会启动非常多的线程,系统将不堪重负。
  • 另外,前面已经看到,在新线程中更新UI还必须要引入handler,这让代码看上去非常臃肿。

为了解决这一问题,Android在1.5版本引入了AsyncTask。AsyncTask的特点是任务在主线程之外运行,而回调方法是在主线程中执行,这就有效地避免了使用Handler带来的麻烦。阅读AsyncTask的源码可知,AsyncTask是使用java.util.concurrent 框架来管理线程以及任务的执行的,concurrent框架是一个非常成熟,高效的框架,经过了严格的测试。这说明AsyncTask的设计很好的解决了匿名线程存在的问题。
AsyncTask是抽象类,其结构图如下图所示:
AsyncTask-class
AsyncTask定义了三种泛型类型 Params,Progress和Result。

  • Params 启动任务执行的输入参数,比如HTTP请求的URL。
  • Progress 后台任务执行的百分比。
  • Result 后台执行任务最终返回的结果,比如String。

子类必须实现抽象方法doInBackground(Params… p) ,在此方法中实现任务的执行工作,比如连接网络获取数据等。通常还应该实现onPostExecute(Result r)方法,因为应用程序关心的结果在此方法中返回。需要注意的是AsyncTask一定要在主线程中创建实例。
AsyncTask的执行分为四个步骤,每一步都对应一个回调方法,需要注意的是这些方法不应该由应用程序调用,开发者需要做的就是实现这些方法。在任务的执行过程中,这些方法被自动调用,运行过程,如下图所示:

AsyncTask-Usage

  • onPreExecute() 当任务执行之前开始调用此方法,可以在这里显示进度对话框。
  • doInBackground(Params…) 此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
  • onProgressUpdate(Progress…) 此方法在主线程执行,用于显示任务执行的进度。
  • onPostExecute(Result) 此方法在主线程执行,任务执行的结果作为此方法的参数返回。

举个简单的例子如下:
// 设置三种类型参数分别为String,Integer,String
class PageTask extends AsyncTask {
// 可变长的输入参数,与AsyncTask.exucute()对应
@Override
protected String doInBackground(String… params) {
try {
HttpClient client = new DefaultHttpClient();
// params[0]代表连接的url
HttpGet get = new HttpGet(params[0]);
HttpResponse response = client.execute(get);
HttpEntity entity = response.getEntity();
long length = entity.getContentLength();
InputStream is = entity.getContent();
String s = null;
if (is != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[128];
int ch = -1;
int count = 0;
while ((ch = is.read(buf)) != -1) {
baos.write(buf, 0, ch);
count += ch;
if (length > 0) {
// 如果知道响应的长度,调用publishProgress()更新进度
publishProgress((int) ((count / (float) length) * 100));
}
// 为了在模拟器中清楚地看到进度,让线程休眠100ms
Thread.sleep(100);
}
s = new String(baos.toByteArray()); }
// 返回结果
return s;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onCancelled() {
super.onCancelled();
}
@Override
protected void onPostExecute(String result) {
// 返回HTML页面的内容
message.setText(result);
}
@Override
protected void onPreExecute() {
// 任务启动,可以在这里显示一个对话框,这里简单处理
message.setText(R.string.task_started);
}
@Override
protected void onProgressUpdate(Integer… values) {
// 更新进度
message.setText(values[0]);
}
}
执行PageTask非常简单,只需要调用如下代码。
PageTask task = new PageTask();
task.execute(url.getText().toString());

总结说明

Handler在前面我们已经学习过,今天突然看到AsyncTask,以及学习其他人的博客基础上,做出了上面的总结,感觉自己收获很多,在这里与大家分享。

 

分享到:
评论

相关推荐

    12_Android 多线程AsyncTask详解

    对于更复杂的多线程需求,如多个并发任务或复杂的线程间通信,可以考虑使用其他并发工具,如IntentService、Handler、Thread配合Looper,或者使用现代的Java并发库如ExecutorService。 总的来说,Android的多线程...

    HandlerThread,AsyncTask,Handler的一个小例子

    本示例探讨了三种不同的方法——HandlerThread、AsyncTask以及Handler,它们都是用来在后台线程处理耗时操作并更新UI(主线程)的有效手段。下面我们将深入理解这三个概念及其在进度条更新中的应用。 首先,...

    异步线程AsyncTask

    首先明确Android之所以有Handler和AsyncTask 都是为了不阻塞主线程(UI线程) 且UI的更新只能在主线程中完成 因此异步处理是不可避免的 Android为了降低这个开发难度 提供了AsyncTask AsyncTask就是一个封装过的...

    Android多线程文件上传

    本主题聚焦于"Android多线程文件上传",我们将探讨如何利用多线程技术来优化文件上传过程,提高效率,并确保应用的响应性。 一、多线程基础 多线程是并发执行多个任务的能力,它允许应用程序同时处理多个任务,提高...

    android Handler Thread AsyncTask httpURLConnection

    在Android开发中,`Handler`、`Thread`、`AsyncTask`和`HttpURLConnection`是四个非常关键的概念,它们涉及到应用程序的多线程处理、网络通信以及UI更新。接下来,我们将详细探讨这些知识点。 首先,`Thread`是Java...

    Android Handler AsyncTask 异步加载

    在Android应用开发中,Handler、AsyncTask和异步加载是三个关键的概念,它们主要用于解决UI线程阻塞问题,提高应用程序的响应速度和用户体验。下面将详细解释这三个概念及其相互关系。 **Handler(处理器)** ...

    Android中AsyncTask实现多线程计数

    本篇将详细讲解如何在Android中使用AsyncTask实现多线程计数,并展示如何将计数结果显示到UI。 首先,我们需要理解Android的线程模型。Android应用的主要工作线程是主线程,也称为UI线程。这个线程负责绘制和交互UI...

    android+threadhandler AsyncTask

    - **线程**:在多线程环境中,线程是程序执行的基本单元。在Android中,主线程负责处理UI交互,而创建新的线程可以让我们在后台执行任务,不阻塞主线程。 - **Handler**:当我们在子线程中完成工作后,通常需要...

    AsyncTask 与Thread加Handler处理消息比较

    总的来说,`AsyncTask`和`Thread+Handler`都是Android中实现异步操作的重要手段,它们各有优缺点,开发者应根据实际项目需求来选择合适的方法。在实践中,理解并熟练掌握这两种方法对于提升Android应用的性能和用户...

    Android多线程操作

    标题"Android多线程操作"和描述"Android多线程开发实例,对使用多线程的用户有一定的参考价值!"暗示我们将深入探讨Android中的线程管理以及如何在实践中有效利用。 Android系统默认运行在主线程,也被称为UI线程,...

    android多线程demo(很清晰很详细)

    本文将深入探讨Android多线程的相关知识点,基于“android多线程demo(很清晰很详细)”的描述,我们将围绕这个示例进行讲解。 1. **线程基础**: - **主线程**:Android应用的UI线程,负责处理用户交互和更新界面。...

    Handler与AsyncTask使用示例

    在Android开发中,`Handler`、`AsyncTask`和`Looper`是三个非常重要的概念,它们主要用于处理应用程序的异步操作和线程通信。本文将深入探讨这些知识点,并通过实例来展示它们如何协同工作。 首先,`Handler`是...

    Android多线程下载

    **一、Android多线程下载** 1. **多线程概念**:多线程是指在一个程序中同时运行多个线程,每个线程处理不同的任务。在下载场景下,多线程意味着将一个大文件分割成多个小部分,每个部分由一个独立的线程负责下载。...

    android线程 Handler Message Queue AsyncTask线程模型 线程交互 + 修改Button样式 示例 最终easy整合版

    在Android开发中,多线程处理是至关重要的,特别是在UI更新和后台任务执行时。本文将深入探讨Android中的线程模型,重点讲解Handler、Message Queue和AsyncTask,并提供修改Button样式的示例以及如何将这些概念整合...

    Android 多线程图片下载开源代码

    1. Android多线程编程:线程池、AsyncTask、Handler/Looper、IntentService 2. 网络请求:HttpURLConnection、OkHttp 3. 图片处理与优化:Bitmap、LruCache、Fresco、Glide 4. 异步编程模型:Callback、LiveData、...

    Android线程操作 handler demo

    此时,Android提供了多种多线程解决方案,其中之一就是Handler机制。本篇将详细讲解如何在Android中使用Handler进行线程间通信。 Handler是Android中处理消息和回调的核心组件,它与Looper和Message紧密配合,实现...

    Android多线程下载(二)

    总之,Android多线程下载涉及到了Android线程模型、并发控制、文件操作等多个方面,需要开发者有扎实的基础知识和实践经验。通过合理利用多线程,不仅可以提升应用性能,还能提高用户满意度。在实际开发中,要根据...

    Android多线程及异步任务消息处理机制 一 Handler的使用

    在Android开发中,多线程和异步任务处理机制是至关重要的,特别是在处理耗时操作如网络请求、数据库操作或大型数据计算时。本篇博文将聚焦于Android中的`Handler`机制,它是Android异步消息处理的核心组件。通过`...

    android多线程断点下载

    总之,Android多线程断点下载是提高用户体验的重要手段,封装好的接口可以让开发者更专注于业务逻辑,而不是复杂的下载实现。通过合理地分块、线程管理和状态保存,我们可以构建一个高效、可靠的下载系统。

    Android多线程处理[参考].pdf

    Android多线程处理是移动应用开发中的关键概念,尤其是在性能优化和用户体验提升方面。Android系统采用的是单线程模型,即主线程(也称为UI线程)主要负责处理用户界面的交互和绘图,包括按键事件、触摸事件以及屏幕...

Global site tag (gtag.js) - Google Analytics