通过前几篇文章的学习,我们已经对Android多线程通信有了一定的了解。那么这篇文章我们来讲讲Android系统为我们内置的异步任务类AsyncTask。运用AsyncTask可以让我们只关注于子线程中的耗时操作和更新UI的操作,使用起来会比Handler要简单一些,当然,只是针对一些简单操作,比如网络操作,图片加载,数据获取等等。
简单介绍
首先AsyncTask是一个抽象类,一般我们使用它会定义一个它的子类并复写其方法来使用,先看类定义:
/**
* Params:启动任务传入参数
* Progress:任务执行进度值
* Result:异步任务完成返回值
*/
public abstract class AsyncTask<Params, Progress, Result> {
}
我们需要传入三个泛型,分别是参数、进度和返回值,其中最重要的几个方法有:
/**
* 主线程中执行,调用execute方法后立即执行
*/
@MainThread
protected void onPreExecute() {
}
/**
* 工作线程中执行,会在执行完onPreExecute后执行方法
* @param Params 接受参数
* @return 返回结果,传递给onPostExecute
*/
@WorkerThread
protected abstract Result doInBackground(Params... params);
/**
* 主线程执行,在手动调用publishProgress后被自动调用
* @param values 异步任务进度
*/
@MainThread
protected void onProgressUpdate(Progress... values) {
}
/**
* 主线程执行,工作任务完成后调用该方法
* @param result 返回结果
*/
@MainThread
protected void onPostExecute(Result result) {
}
执行顺序是这样的,异步任务调用execute
方法后,会立即在UI线程中执行onPreExecute
方法,一般我们会在这里面进行一些初始化操作,紧接着会在开启的子线程中调用doInBackground
方法进行耗时操作,在耗时操作中如果手动调用了publishProgress
方法,系统会自动调用onProgressUpdate
方法更新进度,在异步任务执行完毕后,在UI线程调用并将doInBackground
的返回值作为参数传递给onPostExecute
方法,至此,异步任务完成。
使用实例
下面我们就用一个实际的例子来演示AsyncTask的使用:
class DownloadImageTask extends AsyncTask<String,Void,Bitmap> {
/**
* 主线程中执行,调用execute方法后立即执行
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
pbLoading.setVisibility(View.VISIBLE);
ivContainer.setImageBitmap(null);
}
/**
* 工作线程中执行,会在执行完onPreExecute后执行方法
* @param strings 接受参数
* @return 返回结果,传递给onPostExecute
*/
@Override
protected Bitmap doInBackground(String... strings) {
//下载图片,返回bitmap对象
String url = strings[0];
URLConnection connection;
InputStream inputStream;
Bitmap result = null;
try {
connection = new URL(url).openConnection();
inputStream = connection.getInputStream();
BufferedInputStream bis = new BufferedInputStream(inputStream);
result = BitmapFactory.decodeStream(bis);
bis.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
/**
* 主线程执行,在手动调用publishProgress后被自动调用
* @param values 异步任务进度
*/
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
/**
* 主线程执行,工作任务完成后调用该方法
* @param bitmap 返回结果
*/
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
pbLoading.setVisibility(View.GONE);
ivContainer.setImageBitmap(bitmap);
}
}
很简单的一个下载图片的异步任务,调用方法也很简单:
protected void loadImage(View view) {
asyncTask = new DownloadImageTask();
asyncTask.execute(IMAGE_URL);//可以接受多个参数
}
这里千万要留意使用AsyncTask时定义类型不要直接写AsyncTask,直接用其子类的类型,不然会由于泛型的问题导致ClassCastException,我当年在这儿被坑过,运行效果是这样的:
总结一下AsyncTask的注意事项:
AsyncTask只能在主线程中初始化和执行
AsyncTask的四个重要方法都不由程序员调用,且除了
doInBackground
执行于子线程以外,其他都在主线程中执行取消AsyncTask的方法是,调用
cancle()
方法,并在异步任务执行过程中使用isCanceled
判断,若为false,则终止任务AsyncTask内部线程池默认使用同步线程池,即一个任务完成后执行下一个任务,若要使用异步线程池,使用
asynct.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 0);