标签:
前面几篇文章主要学习了线程以及线程池的创建与使用,今天来学习一下AsyncTask异步任务,学习下AsyncTask到底解决了什么问题?然而它有什么弊端?正所谓知己知彼百战百胜嘛!
我们都知道Android应用程序是单线程模型,在子线程无法直接操作UI主线程,必须通过Handler机制,想了解这方面的知识可以参考这篇文章:Android消息传递之Handler消息机制(一),所以基于这种考虑所以我们一般情况会采用Thread+Handler来处理比较耗时的操作,但是我们都知道每次new Thread()开销比较大,而且缺乏管理,被称为野线程,而且可以无限制创建,之间相互竞争,会导致过多占用系统资源导致系统瘫痪,不利于扩展,比如如定时执行、定期执行、线程中断,这时我们引入了线程池的概念,整个解决问题的模型就变成了Runnable+Executor+Handler,为了降低开发者的开发难度,AsyncTask应运而生,AsyncTask是对线程池的一个封装,使用其自定义的 Executor 来调度线程的执行方式(并发还是串行),并使用 Handler 来完成子线程和主线程数据的共享。
AsyncTask是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度,最后反馈执行的结果给UI主线程.
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);
运行结果
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不与任何组件绑定生命周期,所以在Activity/或者Fragment中创建执行AsyncTask时,最好在Activity/Fragment的onDestory()调用 cancel(boolean);
如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对创建了AsyncTask的Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄 露。
屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。
在Android 1.6之前的版本,AsyncTask是串行的,在1.6至2.3的版本,改成了并行的。在2.3之后的版本又做了修改,可以支持并行和串行,当想要串行执行时,直接执行execute()方法,如果需要并行执行,则要执行executeOnExecutor(Executor)
标签:
原文地址:http://www.cnblogs.com/whoislcj/p/5614937.html