AsyncTask可以让程序进行异步工作,它在一个线程中执行某些操作,之后将结果返回给UI线程。使用AsyncTask类时,需要继承AsyncTask类并实现doInBackground()回调方法。要更新UI界面,需要实现onPostExecute(),并从doInBackground()方法中获得结果,最后,可以在UI线程中调用execute()方法来执行操作,这样就可以安全的更新UI界面。以下贴了谷歌官方的代码,涉及到AsyncTask的简单使用:
public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
/** The system calls this to perform work in a worker thread and * delivers it the parameters given to AsyncTask.execute() */
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
/** The system calls this to perform work in the UI thread and delivers * the result from doInBackground() */
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}
从上面的例子可以看出,AsyncTask的使用非常简单,不用我们去处理Handler和Thread。但是需要注意的是,AsyncTask适用于短时间的操作,最多几秒。如果想要线程长时间在后台运行的话,应该考虑使用Executor,ThreadPoolExecutor和FutureTask。另外,AsyncTask必须在UI线程中加载,AsyncTask的实例要在UI线程中创建,execute方法必须在UI线程中调用。
先一句话概括,三个泛型参数,四个方法。
三个参数:
Params, 任务执行传入参数的类型
Progress, 线程中用于进度更新的单位
Result, 线程执行完成后返回结果的类型
四个方法:
onPreExecute():在UI线程里面调用,在任务执行之前调用,主要做些初始化操作,如弹出ProgressDialog。
doInBackground():在后台线程中调用,处理耗时操作,在这个方法里面,可以调用publishProgress()传递执行的进度值到UI线程,最终在onProgressUpdate()使用。
onProgressUpdate():在UI线程中调用,用于更新进度条。
onPostExecute():在UI线程中调用,在任务执行完成后调用,将得到doInBackground处理得到的结果,用于更新UI。
调用AsyncTask实例的boolean cancel(boolean mayInterruptIfRunning)方法,可以取消任务,会有下面几种情况:
1、如果任务已经完成或者任务已经被取消,那么取消任务失败,返回false。
2、如果任务还没有开始,那么取消成功,这个任务将不会再被执行。
3、如果任务已经在执行,如果ayInterruptIfRunning参数传的是true,那么任务将被中断,如果传的是false,那么任务将继续执行直到完成。调用了这个方法之后,当doInBackground()执行完成后,在UI线程中onPostExecute(Object)将不会再被调用,取而代之的是onCancelled(Object)。
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
如果想要尽快结束任务,那么可以考虑在doInBackground()中写一个循环,定期的检查isCancelled()返回的值,效果图如下:
在Android 3.0之前,异步任务是允许多个线程并行执行的,Android 3.0开始,默认所有的任务放到一个线程中执行,官方的说法是为了避免并行执行引起的错误。
如果想要并行执行的话,需要设置AsyncTask中sDefaultExecutor为THREAD_POOL_EXECUTOR,这样就支持并行执行任务了,对比图:
/** * An {@link Executor} that can be used to execute tasks in parallel. */
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
/** @hide */
public static void setDefaultExecutor(Executor exec) {
sDefaultExecutor = exec;
}
1、在使用时需要得到异步任务的实例,在构造函数中,构造callable对象,重写call方法,构造FutureTask对象,重写done方法,该方法会在FutureTask执行完成后调用。
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
2、调用AsyncTask的execute方法 :
先执行onPreExcute方法,紧接着,调用线程池的execute方法,执行上面构造的FutureTask对象,线程开始执行。
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
线程执行开始执行,先调用doInBackground(mParams)方法,执行耗时任务,在执行过程中,可以调用
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
把执行的进度通过Handler传给onProgressUpdate。执行完成后,得到Result,接着执行postResult方法:
private Result postResult(Result result) {
@SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
postResult方法里面,把得到的Result放到Message中,通过Handler,发送给主线程:
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
Handler处理消息时,会调用finish方法,调用重写的onPostExecute(Result result),整个过程结束。
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}