前言:

前面几篇文章主要学习了线程以及线程池的创建与使用,今天来学习一下AsyncTask异步任务,学习下AsyncTask到底解决了什么问题?然而它有什么弊端?正所谓知己知彼百战百胜嘛!

线程管理相关文章地址:

产生背景:

我们都知道Android应用程序是单线程模型,在子线程无法直接操作UI主线程,必须通过Handler机制,想了解这方面的知识可以参考这篇文章:Android消息传递之Handler消息机制(一),所以基于这种考虑所以我们一般情况会采用Thread+Handler来处理比较耗时的操作,但是我们都知道每次new Thread()开销比较大,而且缺乏管理,被称为野线程,而且可以无限制创建,之间相互竞争,会导致过多占用系统资源导致系统瘫痪,不利于扩展,比如如定时执行、定期执行、线程中断,这时我们引入了线程池的概念,整个解决问题的模型就变成了Runnable+Executor+Handler,为了降低开发者的开发难度,AsyncTask应运而生,AsyncTask是对线程池的一个封装,使用其自定义的 Executor 来调度线程的执行方式(并发还是串行),并使用 Handler 来完成子线程和主线程数据的共享。

AsyncTask介绍

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

AsyncTask主要参数、函数解析

1.)AsyncTask是抽象类.AsyncTask定义了三种泛型类型 Params,Progress和Result
  • Params 启动任务执行的输入参数,比如下载URL
  • Progress 后台任务执行的百分比,比如下载进度
  • Result 后台执行任务最终返回的结果,比如下载结果
2.)继承AsyncTask可以实现的函数
  • onPreExecute()//此函数是在任务没被线程池执行之前调用 运行在UI线程中 比如现在一个等待下载进度Progress,也可以不用实现
  • doInBackground(Params... params)//此函数是在任务被线程池执行时调用 运行在子线程中,在此处理比较耗时的操作 比如执行下载,此函数是抽象函数必须实现
  • onProgressUpdate(Progress... values)//此函数是任务在线程池中执行处于Running状态,回调给UI主线程的进度 比如上传或者下载进度,也可以不用实现
  • onPostExecute(Result result)//此函数任务在线程池中执行结束了,回调给UI主线程的结果 比如下载结果,也可以不用实现
  • onCancelled(Result result)/onCancelled()//此函数表示任务关闭
3.)AsyncTask主要公共函数
  • cancel (boolean mayInterruptIfRunning)//尝试取消这个任务的执行,如果这个任务已经结束或者已经取消或者不能被取消或者某些其他原因,那么将导致这个操作失败,当调用此方法时,此方法执行成功并且这个任务还没有执行,那么此任务将不再执行。如果任务已经开始,这时执行此操作传入的参数mayInterruptIfRunning为true,执行此任务的线程将尝试中断该任务
  • execute (Params... params)//用指定的参数来执行此任务,这个方法将会返回此任务本身,所以调用者可以拥有此任务的引用。此方法必须在UI线程中调用
  • executeOnExecutor(Executor exec,Params... params)//用指定的参数,运行在指定的线程池中,这个方法将会返回此任务本身,所以调用者可以拥有此任务的引用。此方法必须在UI线程中调用
  • get ()//等待计算结束并返回结果
  • get (long timeout, TimeUnit unit)//等待计算结束并返回结果,最长等待时间为:timeOut(超时时间)
  • getStatus ()//获得任务的当前状态  PENDING(等待执行)、RUNNING(正在运行)、FINISHED(运行完成)
  • isCancelled ()//如果在任务正常结束之前取消任务成功则返回true,否则返回false

AsyncTask示例:

1.) 模拟一个下载文件的需求
        String url = "www.xxx.jpg";
AsyncTask<String, Integer, String> asyncTask = new AsyncTask<String, Integer, String>() { @Override
protected void onPreExecute() {//此函数是在任务没被线程池执行之前调用 运行在UI线程中 比如现在一个等待下载进度Progress
super.onPreExecute();
Log.e(TAG, "AsyncTask onPreExecute");
} @Override
protected String doInBackground(String[] params) {//此函数是在任务被线程池执行时调用 运行在子线程中,在此处理比较耗时的操作 比如执行下载
String url = params[0];
Log.e(TAG, "AsyncTask doInBackground url---->" + url);
//模拟下载
int i = 0;
for (i = 20; i <= 100; i += 20) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e(TAG, "AsyncTask doInBackground result--progress-->" + i);
publishProgress(i);
}
String result = "download end";
return result;
} @Override
protected void onProgressUpdate(Integer... values) {//此函数是任务在线程池中执行处于Running状态,回调给UI主线程的进度 比如上传或者下载进度
super.onProgressUpdate(values);
int progress = values[0];
Log.e(TAG, "AsyncTask onProgressUpdate progress---->" + progress);
} @Override
protected void onPostExecute(String s) {//此函数任务在线程池中执行结束了,回调给UI主线程的结果 比如下载结果
super.onPostExecute(s);
Log.e(TAG, "AsyncTask onPostExecute result---->" + s);
} @Override
protected void onCancelled() {//此函数表示任务关闭
super.onCancelled();
Log.e(TAG, "AsyncTask onCancelled");
} @Override
protected void onCancelled(String s) {//此函数表示任务关闭 返回执行结果 有可能为null
super.onCancelled(s);
Log.e(TAG, "AsyncTask onCancelled---->" + s);
}
};
asyncTask.execute(url);

运行结果

2.)如何关闭一个AsyncTask
boolean mayInterruptIfRunning传true的情况还是传false的情况
   if (!asyncTask.isCancelled()) {
boolean isCancel = asyncTask.cancel(true);
Log.e(TAG, "AsyncTask isCancel---->" + isCancel);
}

运行结果:测试发现运行结果一样

通过上面运行结果可以看出,无论mayInterruptIfRunning传入true或者false运行的结果都一样,也就是说当我们调用cancel (boolean mayInterruptIfRunning)函数之后,在doInBackground()return后 ,我们将会调用onCancelled(Object) 不在调用onPostExecute(Object),但是根据运行结果看,我们通过这个函数并没有真正的终止子线程继续运行,只是舍弃了运行结果,AsyncTask不会不考虑结果而直接结束一个线程。调用cancel()其实是给AsyncTask设置一个"canceled"状态。这取决于你去检查AsyncTask是否已经取消,之后决定是否终止你的操作。对于mayInterruptIfRunning——它所作的只是向运行中的线程发出interrupt()调用。在这种情况下,你的线程是不可中断的,也就不会终止该线程,我们可以在doInBackground(Params... params)中定期检查isCancelled()状态,如果检查到已经关闭,直接终止耗时操作。比如上面的下载可以改成

            @Override
protected String doInBackground(String[] params) {//此函数是在任务被线程池执行时调用 运行在子线程中,在此处理比较耗时的操作 比如执行下载
String url = params[0];
Log.e(TAG, "AsyncTask doInBackground url---->" + url);
//模拟下载
int i = 0;
for (i = 20; i <= 100; i += 20) {
if (isCancelled()) {
break;
}
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e(TAG, "AsyncTask doInBackground result--progress-->" + i);
publishProgress(i);
}
if (isCancelled()) {
return "download cancel";
}
String result = "download end";
return result;
}

运行结果

AsyncTask需要注意的地方:

1.)生命周期

AsyncTask不与任何组件绑定生命周期,所以在Activity/或者Fragment中创建执行AsyncTask时,最好在Activity/Fragment的onDestory()调用 cancel(boolean);

2.)内存泄漏

如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对创建了AsyncTask的Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄   露。

3.) 结果丢失

屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。

4.)并行还是串行

在Android 1.6之前的版本,AsyncTask是串行的,在1.6至2.3的版本,改成了并行的。在2.3之后的版本又做了修改,可以支持并行和串行,当想要串行执行时,直接执行execute()方法,如果需要并行执行,则要执行executeOnExecutor(Executor)

Android线程管理之AsyncTask异步任务的更多相关文章

  1. Android线程管理之ThreadLocal理解及应用场景

    前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...

  2. Android线程管理之Thread使用总结

    前言 最近在一直准备总结一下Android上的线程管理,今天先来总结一下Thread使用. 线程管理相关文章地址: Android线程管理之Thread使用总结 Android线程管理之Executo ...

  3. Android线程管理之ExecutorService线程池

    前言: 上篇学习了线程Thread的使用,今天来学习一下线程池ExecutorService. 线程管理相关文章地址: Android线程管理之Thread使用总结 Android线程管理之Execu ...

  4. Android线程管理之ThreadPoolExecutor自定义线程池

    前言: 上篇主要介绍了使用线程池的好处以及ExecutorService接口,然后学习了通过Executors工厂类生成满足不同需求的简单线程池,但是有时候我们需要相对复杂的线程池的时候就需要我们自己 ...

  5. Android线程管理(三)——Thread类的内部原理、休眠及唤醒

    线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...

  6. Android线程管理(二)——ActivityThread

    线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...

  7. Android线程管理(三)——Thread类的内部原理、休眠及唤醒

    线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...

  8. Android线程管理(一)——线程通信

    线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...

  9. Android(java)学习笔记149:Android线程形态之 AsyncTask (异步任务)

    1. AsyncTask和Handler的优缺点比较: 1)AsyncTask实现的原理和适用的优缺点        AsyncTask是Android提供的轻量级的异步类,可以直接继承AsyncTa ...

随机推荐

  1. SignalR系列续集[系列8:SignalR的性能监测与服务器的负载测试]

    目录 SignalR系列目录 前言 也是好久没写博客了,近期确实很忙,嗯..几个项目..头要炸..今天忙里偷闲.继续我们的小系列.. 先谢谢大家的支持.. 我们来聊聊SignalR的性能监测与服务器的 ...

  2. hadoop 2.7.3本地环境运行官方wordcount

    hadoop 2.7.3本地环境运行官方wordcount 基本环境: 系统:win7 虚机环境:virtualBox 虚机:centos 7 hadoop版本:2.7.3 本次先以独立模式(本地模式 ...

  3. 再部署一个 instance 和 Local Network - 每天5分钟玩转 OpenStack(131)

    上一节部署了 cirros-vm1 到 first_local_net,今天我们将再部署 cirros-vm2 到同一网络,并创建 second_local_net. 连接第二个 instance 到 ...

  4. 初探Vue

    Vue.js(读音/vju:/,类似于view),是近来比较火的前端框架,但一直没有怎么具体了解.实现过,就知道个啥的MVVM啦,数据驱动啦,等这些关于Vue的虚概念. 由于最近,小生在公司中,负责开 ...

  5. DDD 领域驱动设计-商品建模之路

    最近在做电商业务中,有关商品业务改版的一些东西,后端的架构设计采用现在很流行的微服务,有关微服务的简单概念: 微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成.系统中的各个微服务可被独 ...

  6. geotrellis使用(二十八)栅格数据色彩渲染(多波段真彩色)

    目录 前言 实现过程 总结 一.前言        上一篇文章介绍了如何使用Geotrellis渲染单波段的栅格数据,已然很是头疼,这几天不懈努力之后工作又进了一步,整清楚了如何使用Geotrelli ...

  7. spring boot 部署为jar

    前言 一直在ide中敲代码,使用命令行mvn spring-boot:run或者gradlew bootRun来运行spring boot项目.想来放到prod上面也应该很简单.然而今天试了下,各种问 ...

  8. JavaScript实现DOM对象选择器

    目的: 根据传入的选择器类型选出第一个符合的DOM对象. ①可以通过id获取DOM对象,例如 $("#adom"); ②可以通过tagName获取DOM对象,例如 $(" ...

  9. 浅谈Slick(2)- Slick101:第一个动手尝试的项目

    看完Slick官方网站上关于Slick3.1.1技术文档后决定开始动手建一个项目来尝试一下Slick功能的具体使用方法.我把这个过程中的一些了解和想法记录下来和大家一起分享.首先我用IntelliJ- ...

  10. CentOS:设置系统级代理(转)

    原文地址:http://www.cnblogs.com/cocowool/archive/2012/07/05/2578487.html YUM代理设置 编辑/etc/yum.conf,在最后加入 # ...