问题一:为什么 AsyncTask 需要在主线程创建和执行?
问题二:为什么 AsyncTask 只能执行一次?结束后还能执行吗?
问题三:AsyncTask 怎么切换线程的?
问题四:AsyncTask 是串行还是并行的?
要使用一个 AsyncTask,首先要创建对象,然后调用它的 execute() 方法。
TestTask task = new TestTask()
task.execute()
那么,我们先来看看它的构造方法是怎么样的。
public AsyncTask() {
this((Looper) null);
}
/**
* @hide
*/
public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
/**
* @hide
*/
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);
}
}
};
}
可以看到,有三个重载的构造方法,而两个有参的构造方法是标注隐藏的,所以我们平时调用的都是无参的构造方法。构造方法里首先给 mHandler 变量赋值,由于我们只能调用无参的构造方法,所以 Looper 参数也就是空的,当参数 Looper 为空或者是主线程获取的 Looper,那么就会调用 getMainHandler() 方法创建一个 Handler 对象并赋值给 mHandler 变量。
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
getMainHandler() 方法里首先会判断 sHandler 不为空,那么就创建一个 InternalHandler 对象赋给 sHandler 变量,而 InternalHandler 继承于 Handler,并且构造方法传入了主线程的 Looper 对象,这也就意味着,sHandler 的对消息的处理就是在主线程中的。
这里我们就可以解答问题一了,为什么要在主线程中创建 AsyncTask,因为 AsyncTask 创建的时候需要获取主线程的 Looper 对象来构造一个 Handler 对象,如果在子线程中创建 AsyncTask,那么获取到的 Looper 对象为空,Handler 的构造就会抛出异常,对 Handler 具体的解析可以看我之前写的 带着问题看 Handler 这篇文章。
然后构造方法又实例化了一个 WorkerRunnable 对象 mWorker,并使用 mWorker 实例化了 FutureTask 对象 mFuture,但是它们并没有得到执行,仅仅只是先进行了实例化。
构造方法到此结束,接下来我们来看看 execute() 方法。
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
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;
}
可以看到,execute() 方法调用了 executeOnExecutor() 方法,在这个方法里面,首先会判断当前 AsyncTask 的状态,如果是已经运行状态或者结束状态,则会抛出异常,所以在这里我们的问题二就得到了解答。
再往下看,先将当前状态置为运行中,然后调用了 onPreExecute() 方法,这个方法由子类实现,可以在任务开始前做一些准备工作,如弹窗提示什么的。然后将我们传入的参数赋给了 mWorker.mParams,接着调用了 exec.execute(mFuture) 方法,exec 是在 execute() 方法中传入的 sDefaultExecutor 对象。
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
跟踪代码可知 sDefaultExecutor 是 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);
}
}
}
SerialExecutor 对象是 AsyncTask 中的一个静态内部类,内部持有了一个 ArrayDeque 队列。SerialExecutor 的 execute() 方法的执行,首先调用 ArrayDeque 的 offer() 方法将新的任务添加到队尾,即之前实例化的 mFuture 对象,然后调用 scheduleNext() 方法,这个方法里,首先调用 ArrayDeque 的 poll() 方法,会将队列里的第一个元素删除并返回,即这里就拿到了处于队头的任务,然后交给 THREAD_POOL_EXECUTOR 来执行。
可以看到 SerialExecutor 的 execute() 方法和 scheduleNext() 方法都加了同步锁,这样一来,如有多个任务到来,这一个一个加入到队列中,然后执行完了头部的任务在执行下一个,直至所有任务执行完毕队列清空,这也就意味着 AsyncTask 的任务是以串行来执行的,在这里我们的问题四就得到了解答。
这里我们可以知道,SerialExecutor 的作用仅仅是保证了任务的串行执行,真正的执行是交给 THREAD_POOL_EXECUTOR 对象的。
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;
}
追溯代码可以看到 THREAD_POOL_EXECUTOR 是一个线程池,在 SerialExecutor 里的 scheduleNext() 方法中,将一个 mActive 交给 THREAD_POOL_EXECUTOR 来执行,而 mActive 是从队列中取出的一个 Runnable 对象。前面已经分析过,SerialExecutor 的 execute() 方法接收的 Runnable 对象是 mFuture,所以mActive 的 run 方法里最终执行了 mFuture 的 run 方法。接下来我们看看 mFuture 的源码
public class FutureTask<V> implements RunnableFuture<V> {
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();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
}
可以看到,mFuture 的 run 方法里会调用构造方法传入的 Callable 对象的 call() 方法,前面分析过,在 mFuture 实例化的时候会传入 mWorker,从而得知,mFuture 的 run() 方法里会调用 mWorker 的call 方法,这里我们在贴一下 mWork 实例化的代码
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;
}
可以看到,在 mWork 的 run 方法里,会调用 doInBackground() 方法,这里也就表明了,doInBackground() 这个方法,最终会在线程池中来执行,这也就解答了我们为什么要在 doInBackground() 中执行耗时任务并且不能更新 UI,因为这个方法的执行是在子线程中的,那么执行耗时任务完毕后如何切换到主线程呢?在执行了 doInBackground() 方法后,始终会执行 postResult(result) 方法,并将 doInBackground() 返回的结果传入。
private Handler getHandler() {
return mHandler;
}
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
可以看到,postResult() 方法就将 doInBackground() 返回的结果封装成了 AsyncTaskResult 对象并使用 mHandler 进行发送,也就是说消息最终会交给 mHandler 进行处理,前面分析过,mHandler 就是 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;
}
}
}
发送的消息会在 handleMessage() 方法里进行处理,如果收到的消息是 MESSAGE_POST_RESULT,也就是 doInBackground() 执行完了并传递结果,执行 AsyncTask 的 finish 方法,如果收到的消息是 MESSAGE_POST_PROGRESS,就回调 onProgressUpdate() 方法,更新进度。
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
如果任务已经取消,就调用 onCancelled() 方法,否则调用 onPostExecute() 方法。到此为止,从 AsyncTask 的创建、任务的执行和结束都从源码也就分析完毕了。
网友评论