为什么AsyncTask只能执行一次,只能用一次execute?
我们点开execute(),可以看到调用了executeOnExecutor()
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
看到executeOnExecutor
@MainThread
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;
}
可以看到这里有一个枚举状态的校验Status共有三种状态,对象初始化时默认为Status.PENDING,其他时候均没有赋值Status.PENDING

为什么AsyncTask默认是串行的?
前面看到默认状态下调用execute方法是带着sDefaultExecutor去调用executeOnExecutor,我们跟一下sDefaultExecutor这个线程池是什么
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
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);
}
}
}
可以看到,每次调用sDefaultExecutor#execute时
-
先把runnable包一层(装饰模式)入队
-
如果目前没有正在执行的任务,即mActive,就尝试从队列中取一个交给另一个线程池去执行
-
每次执行完实际的任务,顺便尝试从队列中取一个交给另一个线程池去执行
由此可见sDefaultExecutor这个静态的线程池就是负责保证任务顺序执行的。 接下来我们看下execute方法是否真的使用了sDefaultExecutor这个线程池去执行任务,上面代码可以看到executeOnExecutor方法在执行onPreExecute()之后就使用sDefaultExecutor去执行任务mFuture,我们看下mFuture是什么:
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
mWorker = new WorkerRunnable<Params, Result>() {
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<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 occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
可以看到mFuture包着mWorker是在构造函数中创建的,看到mFuture的run()
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
...省略代码...
mFuture#run()执行了callable的call方法,而callable正是通过构造带进去的mWorker,其call()方法中赫然就有result = doInBackground(mParams),至此,我们知道了默认情况下用sDefaultExecutor来实现串行,如果你想并行,那就要自己做一个线程池直接调用executeOnExecutor()传进去。
此外,也不难看到AsyncTask四个回调方法中的onPreExecute()是一开始就在调用线程中执行了onPreExecute中又可能做一下跟UI有关的事情,所以规范上execute()必须要主线程调用(如果你的onPreExecute中不需要做一些跟UI有关的事情那就不强求一定要在UI线程调用),而doInBackground()则是在子线程中调用的。
如何确保结果回调onPostExecute()以及进度回调onProgressUpdate()在主线程中执行?
看到mWorker执行完成时调用了postResult(result)
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
这里的Handler跟一下不难发现
private Handler getHandler() {
return mHandler;
}
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
除非你在AsyncTask创建时传入指定的Looper,不然都是默认Looper.getMainLooper()
看到具体实现InternalHandler
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;
}
可以明显看到InternalHandler在这里的作用时用来切线程,不出意外都是切回主线程的,
AsyncTask真的必须在主线程中加载吗?为什么大家都这么说?
旧的AsyncTask源码中sHandler的默认创建是这样的
private static final InternalHandler sHandler=new InternalHandler();
不指定Looper的Handler用的是当先线程的Looper,所以如果你第一次使用在子线程中的话,类加载时,静态变量一并创建,那么sHandler的Looper就不在主线程了,后面的onPostExecute()以及onProgressUpdate()就不在主线程中执行了。
但是,我在28的源码中看到的已经不是这种默认创建的方法了,而是摆明车马指定了Looper.getMainLooper(),那么不管你第一次在哪里加载使用,都不影响切换回主线程了。
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
如何取消一个AsyncTask任务?
我们看到AsyncTask源码中有一个cancel(boolean)方法
public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
跟一下mCancelled

可以看到这是一个线程安全的原子类,顾名思义,它记录了是否被取消的状态
继续跟一下mFuture.cancel(mayInterruptIfRunning)
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
U.compareAndSwapInt(this, STATE, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();
} finally { // final state
U.putOrderedInt(this, STATE, INTERRUPTED);
}
}
} finally {
finishCompletion();
}
return true;
}
当入参为true的时候调用了执行线程的interrupt()
所以我们可以知道,当你调用了cancel()方法时,如果入参为false,那么只是改变一个状态而已,还需要在doInBackground()中适当的地方配合使用,如果入参为true,如果你的操作需要处理会帮你抛InterruptException的话,会帮你抛InterruptException。