1, 基本概念
AsyncTask从名字来看,就是异步任务的意思。
首先看看这个类的定义:
public abstract class AsyncTask<Params, Progress, Result> {
•••
}
AsyncTask是一个抽象类,同样,有4个抽象函数,
onPreExecute //主线程,执行任务之前的一些UI操作
doInBackground //子线程,执行任务
onProgressUpdate // 任务执行时更新进度信息
onPostExecute // 主线程,任务完成时更新UI
所以,我们自定义的类必须继承AsyncTask并且实现4个抽象函数,并且主动调用execute方法。
看看AsyncTask的构造函数:
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(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);
}
}
};
}
2, 流程图
从调用execute函数开始,
流程图如下:
3, 任务入队列
详细解析代码:
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@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;
}
1, Status是一个枚举类型,它的值标志着任务执行的状态,初始值为PENDING,并且一个任务只能执行一次。
private volatileStatus mStatus = Status.PENDING;
2,由mWorker 和mFuture的初始化可知, mWorker是供mFuture回调的,并且仅有一个call回调函数。mFuture是一个封装的线程类,关键点是这个子线程什么时候执行。
3, 形参exec即是sDefaultExecutor,是AsyncTask内部类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);
}
}
}
Executor主要做2件事情:
1,调用ArrayDeque的offer方法将子线程(包含任务)入队列。
2,调用ArrayDeque的poll方法对该队列进行出队列操作(先进先出)。
ArrayDeque的队列elements其实是一个数组: private transient Object[] elements;
3,调用THREAD_POOL_EXECUTOR将该子线程放入线程池。
SerialExecutor类和THREAD_POOL_EXECUTOR对象都是static的,也即是说,无论有多少个AsyncTask子对象,他们都是唯一的,这样才能统一管理各个线程。
4,任务执行
流程图中的第8到16步骤是执行任务, 线程池的原理在此就不论述了。
最后还是会通过mFuture调用mWorker的call函数来执行,只是执行的线程在线程池当中,还是看AsyncTask构造函数中的call函数
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
};
首先调用doInBackground方法执行任务,然后执行完成之后调用postResult方法。
执行完任务之后如何切换到主线程中呢?
通过postResult方法发送消息,利用Handler机制回到主线程中,步骤19到22就是这一过程。
另外,在自写的doInBackground方法的耗时操作时,可以调用publishProgress方法告知主线程任务执行的进度,
publishProgress最后也会调用postResult方法通过Handler机制切换到主线程并且调用onProgressUpdate方法。