文档章节

细谈AsyncTask

jacky_123
 jacky_123
发布于 2015/01/18 19:22
字数 2063
阅读 133
收藏 3

android AsyncTask介绍

AsyncTask和Handler对比

1 ) AsyncTask实现的原理,和适用的优缺点

AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.

使用的优点:

l  简单,快捷

l  过程可控   

使用的缺点:

l  在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.

2 )Handler异步实现的原理和适用的优缺点

在Handler 异步实现时,涉及到 Handler, Looper, Message,Thread四个对象,实现异步的流程是主线程启动Thread(子线程)àthread(子线程)运行并生成Message-àLooper获取Message并传递给HandleràHandler逐个获取Looper中的Message,并进行UI变更。

使用的优点:

l  结构清晰,功能定义明确

l  对于多个后台任务时,简单,清晰

AsyncTask介绍

Android的AsyncTask比Handler更轻量级一些,适用于简单的异步处理。

首先明确Android之所以有Handler和AsyncTask,都是为了不阻塞主线程(UI线程),且UI的更新只能在主线程中完成,因此异步处理是不可避免的。

Android为了降低这个开发难度,提供了AsyncTask。AsyncTask就是一个封装过的后台任务类,顾名思义就是异步任务。

AsyncTask直接继承于Object类,位置为android.os.AsyncTask。要使用AsyncTask工作我们要提供三个泛型参数,并重载几个方法(至少重载一个)。

AsyncTask定义了三种泛型类型 Params,Progress和Result。

  • Params 启动任务执行的输入参数,比如HTTP请求的URL。

  • Progress 后台任务执行的百分比。

  • Result 后台执行任务最终返回的结果,比如String,Bitmap等。

使用过AsyncTask 的同学都知道一个异步加载数据最少要重写以下这两个方法:

  • doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。

  • onPostExecute(Result)  相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回

有必要的话你还得重写以下这三个方法,但不是必须的:

  • onProgressUpdate(Progress…)   可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。

  • onPreExecute()        这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。

  • onCancelled()             用户调用取消时,要做的操作

使用AsyncTask类,以下是几条必须遵守的准则:

  • Task的实例必须在UI thread中创建;

  • execute方法必须在UI thread中调用;

  • 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;

  • 该task只能被执行一次,否则多次调用时将会出现异常;

介绍一个简单例子。了解一下 AsyncTask的运行过程。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/textView01"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
    <ProgressBar
        android:id="@+id/progressBar02"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/button03"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="更新progressbar" />
</LinearLayout>

MainActivity.java:

public class MainActivity extends Activity {
 private Button button;
 private ProgressBar progressBar;
 private TextView textView;
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  button = (Button) findViewById(R.id.button03);
  progressBar = (ProgressBar) findViewById(R.id.progressBar02);
  textView = (TextView) findViewById(R.id.textView01);
  button.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
    ProgressBarAsyncTask asyncTask = new ProgressBarAsyncTask(
      textView, progressBar);
    asyncTask.execute(1000);
   }
  });
 }
}

 

ProgressBarAsyncTask.java:

/**
 * 生成该类的对象,并调用execute方法之后 首先执行的是onProExecute方法 其次执行doInBackgroup方法
 * 
 */
public class ProgressBarAsyncTask extends AsyncTask<Integer, Integer, String> {
 private TextView textView;
 private ProgressBar progressBar;
 public ProgressBarAsyncTask(TextView textView, ProgressBar progressBar) {
  super();
  this.textView = textView;
  this.progressBar = progressBar;
 }
 /**
  * 这里的Integer参数对应AsyncTask中的第一个参数 这里的String返回值对应AsyncTask的第三个参数
  * 该方法并不运行在UI线程当中,主要用于异步操作,所有在该方法中不能对UI当中的空间进行设置和修改
  * 但是可以调用publishProgress方法触发onProgressUpdate对UI进行操作
  */
 @Override
 protected String doInBackground(Integer... params) {
  NetOperator netOperator = new NetOperator();
  int i = 0;
  for (i = 10; i <= 100; i += 10) {
   netOperator.operator();
   publishProgress(i);
  }
  return i + params[0].intValue() + "";
 }
 /**
  * 这里的String参数对应AsyncTask中的第三个参数(也就是接收doInBackground的返回值)
  * 在doInBackground方法执行结束之后在运行,并且运行在UI线程当中 可以对UI控件进行设置
  */
 @Override
 protected void onPostExecute(String result) {
  textView.setText("异步操作执行结束" + result);
 }
 // 该方法运行在UI线程当中,并且运行在UI线程当中 可以对UI控件进行设置
 @Override
 protected void onPreExecute() {
  textView.setText("开始执行异步线程");
 }
 /**
  * 这里的Intege参数对应AsyncTask中的第二个参数
  * 在doInBackground方法当中,,每次调用publishProgress方法都会触发onProgressUpdate执行
  * onProgressUpdate是在UI线程中执行,所有可以对UI控件进行操作
  */
 @Override
 protected void onProgressUpdate(Integer... values) {
  int value = values[0];
  progressBar.setProgress(value);
  textView.setText("执行异步线程"+value);
 }
}

NetOperator.java:

public class NetOperator {

 public void operator() {

  try {

   // 休眠1秒

   Thread.sleep(1000);

  } catch (InterruptedException e) {

   // TODO Auto-generated catch block

   e.printStackTrace();

  }

 }

}

 

再以开发瀑布流照片为例子。里面涉及的知识很广,大家好好斟酌看看。

/**
  * 异步下载图片的任务。
  * 
  * @author guolin
  */
 class LoadImageTask extends AsyncTask<String, Void, Bitmap> {
  /**
   * 图片的URL地址
   */
  private String mImageUrl;
  /**
   * 可重复使用的ImageView
   */
  private ImageView mImageView;
  public LoadImageTask() {
  }
  /**
   * 将可重复使用的ImageView传入
   * 
   * @param imageView
   */
  public LoadImageTask(ImageView imageView) {
   mImageView = imageView;
  }
  @Override
  protected Bitmap doInBackground(String... params) {
   mImageUrl = params[0];
   Bitmap imageBitmap = imageLoader.getBitmapFromMemoryCache(mImageUrl);
   if (imageBitmap == null) {
    imageBitmap = loadImage(mImageUrl);
   }
   return imageBitmap;
  }
  @Override
  protected void onPostExecute(Bitmap bitmap) {
   if (bitmap != null) {
    double ratio = bitmap.getWidth() / (columnWidth * 1.0);
    int scaledHeight = (int) (bitmap.getHeight() / ratio);
    addImage(bitmap, columnWidth, scaledHeight);
   }
   taskCollection.remove(this);
  }
  /**
   * 根据传入的URL,对图片进行加载。如果这张图片已经存在于SD卡中,则直接从SD卡里读取,否则就从网络上下载。
   * 
   * @param imageUrl
   *            图片的URL地址
   * @return 加载到内存的图片。
   */
  private Bitmap loadImage(String imageUrl) {
   File imageFile = new File(getImagePath(imageUrl));
   if (!imageFile.exists()) {
    downloadImage(imageUrl);
   }
   if (imageUrl != null) {
    Bitmap bitmap = ImageLoader.decodeSampledBitmapFromResource(imageFile.getPath(),
      columnWidth);
    if (bitmap != null) {
     imageLoader.addBitmapToMemoryCache(imageUrl, bitmap);
     return bitmap;
    }
   }
   return null;
  }
  /**
   * 向ImageView中添加一张图片
   * 
   * @param bitmap
   *            待添加的图片
   * @param imageWidth
   *            图片的宽度
   * @param imageHeight
   *            图片的高度
   */
  private void addImage(Bitmap bitmap, int imageWidth, int imageHeight) {
   LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(imageWidth,
     imageHeight);
   if (mImageView != null) {
    mImageView.setImageBitmap(bitmap);
   } else {
    ImageView imageView = new ImageView(getContext());
    imageView.setLayoutParams(params);
    imageView.setImageBitmap(bitmap);
    imageView.setScaleType(ScaleType.FIT_XY);
    imageView.setPadding(5, 5, 5, 5);
    imageView.setTag(R.string.image_url, mImageUrl);
    imageView.setOnClickListener(new OnClickListener() {
     @Override
     public void onClick(View v) {
      Intent intent = new Intent(getContext(), ImageDetailsActivity.class);
      intent.putExtra("image_path", getImagePath(mImageUrl));
      getContext().startActivity(intent);
     }
    });
    findColumnToAdd(imageView, imageHeight).addView(imageView);
    imageViewList.add(imageView);
   }
  }
  /**
   * 找到此时应该添加图片的一列。原则就是对三列的高度进行判断,当前高度最小的一列就是应该添加的一列。
   * 
   * @param imageView
   * @param imageHeight
   * @return 应该添加图片的一列
   */
  private LinearLayout findColumnToAdd(ImageView imageView, int imageHeight) {
   if (firstColumnHeight <= secondColumnHeight) {
    if (firstColumnHeight <= thirdColumnHeight) {
     imageView.setTag(R.string.border_top, firstColumnHeight);
     firstColumnHeight += imageHeight;
     imageView.setTag(R.string.border_bottom, firstColumnHeight);
     return firstColumn;
    }
    imageView.setTag(R.string.border_top, thirdColumnHeight);
    thirdColumnHeight += imageHeight;
    imageView.setTag(R.string.border_bottom, thirdColumnHeight);
    return thirdColumn;
   } else {
    if (secondColumnHeight <= thirdColumnHeight) {
     imageView.setTag(R.string.border_top, secondColumnHeight);
     secondColumnHeight += imageHeight;
     imageView.setTag(R.string.border_bottom, secondColumnHeight);
     return secondColumn;
    }
    imageView.setTag(R.string.border_top, thirdColumnHeight);
    thirdColumnHeight += imageHeight;
    imageView.setTag(R.string.border_bottom, thirdColumnHeight);
    return thirdColumn;
   }
  }
  /**
   * 将图片下载到SD卡缓存起来。
   * 
   * @param imageUrl
   *            图片的URL地址。
   */
  private void downloadImage(String imageUrl) {
   if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
    Log.d("TAG", "monted sdcard");
   } else {
    Log.d("TAG", "has no sdcard");
   }
   HttpURLConnection con = null;
   FileOutputStream fos = null;
   BufferedOutputStream bos = null;
   BufferedInputStream bis = null;
   File imageFile = null;
   try {
    URL url = new URL(imageUrl);
    con = (HttpURLConnection) url.openConnection();
    con.setConnectTimeout(5 * 1000);
    con.setReadTimeout(15 * 1000);
    con.setDoInput(true);
    con.setDoOutput(true);
    bis = new BufferedInputStream(con.getInputStream());
    imageFile = new File(getImagePath(imageUrl));
    fos = new FileOutputStream(imageFile);
    bos = new BufferedOutputStream(fos);
    byte[] b = new byte[1024];
    int length;
    while ((length = bis.read(b)) != -1) {
     bos.write(b, 0, length);
     bos.flush();
    }
   } catch (Exception e) {
    e.printStackTrace();
   } finally {
    try {
     if (bis != null) {
      bis.close();
     }
     if (bos != null) {
      bos.close();
     }
     if (con != null) {
      con.disconnect();
     }
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
   if (imageFile != null) {
    Bitmap bitmap = ImageLoader.decodeSampledBitmapFromResource(imageFile.getPath(),
      columnWidth);
    if (bitmap != null) {
     imageLoader.addBitmapToMemoryCache(imageUrl, bitmap);
    }
   }
  }
  /**
   * 获取图片的本地存储路径。
   * 
   * @param imageUrl
   *            图片的URL地址。
   * @return 图片的本地存储路径。
   */
  private String getImagePath(String imageUrl) {
   int lastSlashIndex = imageUrl.lastIndexOf("/");
   String imageName = imageUrl.substring(lastSlashIndex + 1);
   String imageDir = Environment.getExternalStorageDirectory().getPath()
     + "/PhotoWallFalls/";
   File file = new File(imageDir);
   if (!file.exists()) {
    file.mkdirs();
   }
   String imagePath = imageDir + imageName;
   return imagePath;
  }
 }

 

© 著作权归作者所有

jacky_123
粉丝 3
博文 55
码字总数 26297
作品 0
南通
程序员
私信 提问
Java程序员从笨鸟到菜鸟全部博客目录【2012年十一月七日更新】

本文来自:曹胜欢博客专栏。转载请注明出处:http://blog.csdn.net/csh624366188 大学上了一年半,接触java也一年半了,虽然中间也有其他东西的学习,但是还是以java为主路线,想想这一年半,...

长平狐
2012/11/12
133
0
Java程序员从笨鸟到菜鸟全部博客目录【2012年十一月七日更新】

本文来自:曹胜欢博客专栏。转载请注明出处:http://blog.csdn.net/csh624366188 大学上了一年半,接触java也一年半了,虽然中间也有其他东西的学习,但是还是以java为主路线,想想这一年半,...

长平狐
2012/11/12
209
0
《Java程序员由笨鸟到菜鸟》电子版书正式发布,欢迎大家下载

在众多朋友的支持和鼓励下,《Java程序员由菜鸟到笨鸟》电子版终于和大家见面了。本电子书涵盖了从java基础到javaweb开放框架的大部分内容。在编写的过程中,难免会出现一些错误,希望大家能...

长平狐
2012/11/12
243
0
《Java程序员由笨鸟到菜鸟》电子版书正式发布,欢迎大家下载

在众多朋友的支持和鼓励下,《Java程序员由菜鸟到笨鸟》电子版终于和大家见面了。本电子书涵盖了从java基础到javaweb开放框架的大部分内容。在编写的过程中,难免会出现一些错误,希望大家能...

长平狐
2012/11/12
142
0
细谈编程语言创建的后台服务---my note

就拿c#编程语言来说吧: 用c#中创建一个windows服务非常简单,与windows服务相关的类都在System.ServiceProcess命名空间下。 每个服务都需要继承自ServiceBase类,并重写相应的启动、暂停、停...

crossmix
2016/03/03
42
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring Boot + Mybatis-Plus 集成与使用(二)

前言: 本章节介绍MyBatis-Puls的CRUD使用。在开始之前,先简单讲解下上章节关于Spring Boot是如何自动配置MyBatis-Plus。 一、自动配置 当Spring Boot应用从主方法main()启动后,首先加载S...

伴学编程
昨天
7
0
用最通俗的方法讲spring [一] ──── AOP

@[TOC](用最通俗的方法讲spring [一] ──── AOP) 写这个系列的目的(可以跳过不看) 自己写这个系列的目的,是因为自己是个比较笨的人,我曾一度怀疑自己的智商不适合干编程这个行业.因为在我...

小贼贼子
昨天
7
0
Flutter系列之在 macOS 上安装和配置 Flutter 开发环境

本文为Flutter开发环境在macOS下安装全过程: 一、系统配置要求 想要安装并运行 Flutter,你的开发环境需要最低满足以下要求: 操作系统:macOS(64位) 磁盘空间:700 MB(不包含 IDE 或其余...

過愙
昨天
6
0
OSChina 周六乱弹 —— 早上儿子问我他是怎么来的

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @凉小生 :#今日歌曲推荐# 少点戾气,愿你和这个世界温柔以待。中岛美嘉的单曲《僕が死のうと思ったのは (曾经我也想过一了百了)》 《僕が死の...

小小编辑
昨天
2.5K
16
Excption与Error包结构,OOM 你遇到过哪些情况,SOF 你遇到过哪些情况

Throwable 是 Java 中所有错误与异常的超类,Throwable 包含两个子类,Error 与 Exception 。用于指示发生了异常情况。 Java 抛出的 Throwable 可以分成三种类型。 被检查异常(checked Exc...

Garphy
昨天
42
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部