1、概述
AsyncTask是一个轻量级的异步任务类,并可以将结果与执行进度实时传递给主线程,让主线程进行UI更新。
2、相关参数与方法
- public abstract class AsyncTask
。三个泛型参数分别代表了参数值类型,进度类型,返回结果类型。 - onPreExecute(),在主线程中执行,在异步任务开始之前调用。
- doInBackground(Params...params),在线程池中执行,用来进行异步任务。
- publishProgress(Progress... values),可以在doInBackground方法中进行调用来通知主线程中更新进度的方法,来进行进度更新
- onProgressUpdate(Progress... values) ,主线程中更新进度的方法。用来更新UI中的进度
- onPostExecute(Result result),当正常完成的时候,调用的方法,此方法也在主线程中执行。
- onCancelled(),当任务被取消的时候此方法会被调用,onPostExecute方法不会被调用。
3、基本使用
任务所需参数类型为String,进度类型为Integer,返回结果类型为String
class MyAsyncTask extends AsyncTask{
@Override
protected void onPreExecute() {
super.onPreExecute();
//Todo:做一些准备与初始化操作。
}
@Override
protected String doInBackground(String... strings) {
//Todo:异步任务
//Todo:通知进度
publishProgress(10);
if (isCancelled()){
//Todo:判断任务是否被取消掉了,如果被取消掉了,就停止异步任务
return "";
}
//返回结果
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
//Todo:得到进度并更新UI
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
//Todo:任务完成之后会进行调用。如果任务被取消将不会调用此方法。
}
@Override
protected void onCancelled() {
super.onCancelled();
//Todo:任务被取消之后会进行调用。
}
}
//创建实例对象并使用execute开始任务,参数为处理任务所要参数。
new MyAsyncTask().execute("www.baidu.com");
4、原理分析
- 首先我们来看一下AsyncTask的构造方法
public AsyncTask() {
this((Looper) null);
}
public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
mWorker = new WorkerRunnable() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
mFuture = new FutureTask(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 occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
- 从27的AsyncTask源码中我们可以看出:第一步:AsyncTask有三个构造方法,最终都会调用AsyncTask(@Nullable Looper callbackLooper)这个构造方法,首先AsyncTask会初始化一个Handler用来处理消息,而默认情况下,会拿我们主线程的looper构建我们的Handler,所以我们所有的消息处理都是在主线程当中的。
- 第二部,AysncTask将我们参数与返回值封装成一个WorkerRunnable对象,又将WorkerRunnable封装为FutureTask(执行在线程中的Runnable),FutureTask中的run方法会调用WorkerRunnable的Call方法,在任务执行的时候(在线程池中被子线程)被调用,mTaskInvoked会设置为true表示任务已经执行,然后调用doInBackgroud方法传入参数并返回result结果,并最终调用postResult返回结果。
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
message.sendToTarget();
return result;
}
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@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;
}
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
通过pstResult的源码我们可以看出。使用了Handler发送了一个消息,而我们的Handler在默认构造的时候是InternalHandler 。可以看到处理MESSAGE_POST_RESULT的时候调用的finish方法,判断是否是被取消,如果被取消就调用onCancelled方法,如果没有被取消调用onPostExecute方法, 所以onCancellde和onPostExecute方法都是在主线程中执行的。
- 接下来我们来分析任务是怎么异步进行的。我们从execute方法来分析。
public final AsyncTask execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask 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;
}
execute方法调用了executeOnExecutor方法。在这个方法中我们可以看到首先调用onPreExecute()方法;此方法会在AsyncTask.execute方法调用的线程中执行。最先执行的方法。然后调用exec.execute(mFuture)方法,exec是一个SerialExecutor对象
private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
从它的源码中我们可以看出,他是一个线程池。但是他里面只有一个存放任务的ArrayDeque队列。在execute方法中用offer方法把任务加到队列当中,如果没有任务在执行的话就调用scheduleNext方法执行任务,而当任务完成之后如果还有任务,还会调用这个方法继续执行,从这里我们可以看出AsyncTask方法是串行执行任务的。我们在scheduleNext方法中可以看到其调用了THREAD_POOL_EXECUTOR的execute方法执行任务,而THREAD_POOL_EXECUTOR是一个线程池。所以这里才是真正执行任务的线程池。
对于publishProgress和onProgressUpdate这两个方法的源码大家可以自己看一下,只是用了handler将消息发送到主线程而已,源码比较简单。
5、各版本中的差异
在Android1.6之前AsyncTask是串行执行任务的,在1.6的时候修改成了线程池并行处理任务,但是从3.0开始,为了避免并发错误,又改为用一个线程串行执行任务,但是保留了executeOnExecutor方法来并行的执行任务,参数为THREAD_POOL_EXECUTOR。