Android线程管理之AsyncTask异步任务
前言:
前面几篇文章主要学习了线程以及线程池的创建与使用,今天来学习一下AsyncTask异步任务,学习下AsyncTask到底解决了什么问题?然而它有什么弊端?正所谓知己知彼百战百胜嘛!
线程管理相关文章地址:
- Android线程管理之Thread使用总结
- Android线程管理之ExecutorService线程池
- Android线程管理之ThreadPoolExecutor自定义线程池
- Android线程管理之AsyncTask异步任务
- Android线程管理之ThreadLocal理解及应用场景
产生背景:
我们都知道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异步任务的更多相关文章
- Android线程管理之ThreadLocal理解及应用场景
前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...
- Android线程管理之Thread使用总结
前言 最近在一直准备总结一下Android上的线程管理,今天先来总结一下Thread使用. 线程管理相关文章地址: Android线程管理之Thread使用总结 Android线程管理之Executo ...
- Android线程管理之ExecutorService线程池
前言: 上篇学习了线程Thread的使用,今天来学习一下线程池ExecutorService. 线程管理相关文章地址: Android线程管理之Thread使用总结 Android线程管理之Execu ...
- Android线程管理之ThreadPoolExecutor自定义线程池
前言: 上篇主要介绍了使用线程池的好处以及ExecutorService接口,然后学习了通过Executors工厂类生成满足不同需求的简单线程池,但是有时候我们需要相对复杂的线程池的时候就需要我们自己 ...
- Android线程管理(三)——Thread类的内部原理、休眠及唤醒
线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...
- Android线程管理(二)——ActivityThread
线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...
- Android线程管理(三)——Thread类的内部原理、休眠及唤醒
线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...
- Android线程管理(一)——线程通信
线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...
- Android(java)学习笔记149:Android线程形态之 AsyncTask (异步任务)
1. AsyncTask和Handler的优缺点比较: 1)AsyncTask实现的原理和适用的优缺点 AsyncTask是Android提供的轻量级的异步类,可以直接继承AsyncTa ...
随机推荐
- ES5对Array增强的9个API
为了更方便的对Array进行操作,ES5规范在Array的原型上新增了9个方法,分别是forEach.filter.map.reduce.reduceRight.some.every.indexOf ...
- Syscan360会议胸牌破解揭秘
Syscan360会议胸牌破解揭秘 背景 有幸参加今年11月份的上海Syscan360安全会议,会议期间有一个亮点就是360的独角兽团队设计了一款电子badge(胸牌)供参加人员进行破解尝试,类似于美 ...
- 23种设计模式--工厂模式-Factory Pattern
一.工厂模式的介绍 工厂模式让我们相到的就是工厂,那么生活中的工厂是生产产品的,在代码中的工厂是生产实例的,在直白一点就是生产实例的类,代码中我们常用new关键字,那么这个new出来的实例 ...
- 简约之美Jodd-http--深入源码理解http协议
Jodd 是一个开源的 Java 工具集, 包含一些实用的工具类和小型框架.简单,却很强大! jodd-http是一个轻巧的HTTP客户端.现在我们以一个简单的示例从源码层看看是如何实现的? Http ...
- C#——传值参数(2)
//我的C#是跟着猛哥(刘铁猛)(算是我的正式老师)<C#语言入门详解>学习的,微信上猛哥也给我讲解了一些不懂得地方,对于我来说简直是一笔巨额财富,难得良师! 这次与大家共同学习C#中的 ...
- java 设计模式
目录: 设计模式六大原则(1):单一职责原则 设计模式六大原则(2):里氏替换原则 设计模式六大原则(3):依赖倒置原则 设计模式六大原则(4):接口隔离原则 设计模式六大原则(5):迪米特法则 设计 ...
- jQuery个性化图片轮播效果
jQuery个性化图片轮播效果 购物产品展示:图片轮播器<效果如下所示> 思路说明: 每隔一段时间,实现图片的自动切换及选项卡选中效果,鼠标划入图片动画停止,划出或离开动画开始 两个区域: ...
- Xamarin Android 应用程序内图标上数字提示
最近在用 Xamarin 做一个 Android 应用,打开应用时,如果有新消息,需要在应用内的 Toolbar 或者首页的图标上显示数字提示.在这里和大家分享一下实现方法,如果你有更新好的实现方法, ...
- Struts2数据校验
Struts2数据校验 1.常见数据校验方法 表单数据的校验方式: 表单中的数据必须被效验以后才能够被使用,常用的效验方式分为两种: 前台校验:也称之为客户端效验,主要是通过JS编程的方式进行表单数据 ...
- Xamarin.iOS开发初体验
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKwAAAA+CAIAAAA5/WfHAAAJrklEQVR4nO2c/VdTRxrH+wfdU84pW0