AsyncTask可以用来处理一些后台较耗时的任务,查看源码发现其内部就是一个Handler和线程池的封装,可以帮助我们处理耗时任务的同时去更新UI。
1.1 AsyncTask抽象类的3参数
public abstract class AsyncTask<Params, Progress, Result> {
......
}
- Params 启动任务执行的输入参数(
new DownloadTask().execute(Params);
) - Progress 后台任务执行的百分比(
publishProgress(Progres);
),比如下载进度 - Result 后台执行任务最终返回的结果,比如下载结果
1.2 继承AsyncTask可以实现的函数
-
onPreExecute()
:(运行在UI线程中,非必须方法,可以不用实现)
这个方法会在后台任务开始执行之间调用,通常用来做一些准备操作,比如下载文件任务执行前,在这个方法中显示一个进度条。 -
doInBackground(Params... params)
:(运行在子线程中,此函数是抽象函数必须实现)
在任务被线程池执行时调用 ,可以在此方法中处理比较耗时的操作,比如下载文件等等。在这个方法中是不可以进行UI操作的,如果需要更新UI元素,比如说反馈当前任务的执行进度,可以调用 publishProgress(Progress…) 方法来完成。 -
onProgressUpdate(Progress... values)
:(运行在UI线程中,非必须方法,可以不用实现)
当在后台任务中调用了publishProgress(Progress…) 方法后,这个方法就很快会被调用,方法中携带的参数就是在后台任务中传递过来的。此函数是任务在线程池中执行处于Running状态,回调给UI主线程的进度,比如上传或者下载进度。 -
onPostExecute(Result result)
:(运行在UI线程中,非必须方法,可以不用实现)
当doInBackground(Params…) 执行完毕并通过return语句进行返回时,这个方法就很快会被调用。返回的数据会作为参数传递到此方法中。此函数代表任务在线程池中执行结束了,回调给UI主线程的结果。比如下载结果。 -
onCancelled(Result result)
:(运行在UI线程中,非必须方法,可以不用实现)
当异步任务取消时,onCancelled()会被调用,这个时候onPostExecute()则不会被调用。
1.3 AsyncTask常用的方法
cancel (boolean mayInterruptIfRunning)
尝试取消这个任务的执行(如果这个任务已经结束或者已经取消或者不能被取消或者某些其他原因,那么将导致这个操作失败)execute (Params... params)
用指定的参数来执行此任务(此方法必须在UI线程中调用,因为要将handler绑定到主线程的Looper,方便后台任务执行完毕后,由后台线程切换到UI线程去更新UI)。executeOnExecutor(Executor exec,Params... params)
用指定的参数行此任务,并运行在指定的线程池中(此方法必须在UI线程中调用)getStatus()
获得任务的当前状态 PENDING(等待执行)、RUNNING(正在运行)、FINISHED(运行完成)isCancelled()
在任务正常结束之前能成功取消任务则返回true,否则返回false
1.4 使用示例
public class ImageText extends Activity {
MyAsyncTask mytask;
ImageView imageView;
ProgressBar progressBar;
String URL = "http://b.zol-img.com.cn/sjbizhi/images/4/320x510/1366618073898.jpg";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.imagetext);
imageView = (ImageView) findViewById(R.id.imageview_imagetext);
progressBar = (ProgressBar) findViewById(R.id.progress_imagetext);
//开始异步加载图片——传入图片的URL
mytask = new MyAsyncTask();
mytask.execute(URL);
}
//将AsyncTask和activity生命周期绑定-暂停状态时候去终止异步操作
@Override
protected void onPause() {
super.onPause();
//运行状态
if (mytask != null && mytask.getStatus() == AsyncTask.Status.RUNNING) {
//cancel方法只是将对应的AsyncTask标记为cancel状态,并没有真正的取消线程的执行。
mytask.cancel(true);
}
}
//3泛型:url类型,void(不要进度),返回值类型
class MyAsyncTask extends AsyncTask<String,Void,Bitmap>{
//第一阶段————准备阶段让进度条显示
@Override
protected void onPreExecute() {
super.onPreExecute();
progressBar.setVisibility(View.VISIBLE);
}
//第二阶段——网络获取图片
@Override
protected Bitmap doInBackground(String... params) {
//从可变参数的数组中拿到第0位的图片地址
String newurl = params[0];
Bitmap bitmap = null;
URLConnection urlConnection;
InputStream is = null;
//图片下载操作
try {
urlConnection = new URL(newurl).openConnection();
is = urlConnection.getInputStream();
BufferedInputStream bf=new BufferedInputStream(is);
//图片加载的太快,可以用线程睡眠
Thread.sleep(1000);
bitmap = BitmapFactory.decodeStream(bf);
is.close();
bf.close();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
//返回结果bitmap
return bitmap;
}
//第三阶段,拿到结果bitmap图片,更新ui
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
progressBar.setVisibility(View.GONE);
imageView.setImageBitmap(bitmap);
}
}
}
上面AsyncTask.cancel方法只是将对应的AsyncTask标记为cancel状态,并没有真正的取消线程的执行。会在任务执行时候判断是cancel状态,才会终止任务的执行。
1.5 注意点
(1)AsyncTask不与任何组件绑定生命周期
在Activity/或者Fragment中创建执行AsyncTask时,最好在Activity/Fragment的onDestory()调用 cancel(true);
(2)内存泄漏
如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对创建了AsyncTask的Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄露。
(3)屏幕旋转
屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。