AsyncTask类结构分析
public abstract class AsyncTask<Params, Progress, Result> {
// 下面几个都是new线程池的一些参数,就不具体解释了
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
// 这个线程池是负责管理任务执行的。注意,是static修饰的,整个应用的所有AsyncTask共用
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;
}
// 任务执行中、执行完成,通过handler通知主线程
private static InternalHandler sHandler;
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
// 这个是存储任务的线程池,也是static修饰的,所有AsyncTask共用这一个线程池存储任务
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
// 这个是负责执行结果回调的Callback对象(并没有继承Runnable)
private final WorkerRunnable<Params, Result> mWorker;
// 这个继承Runnable,负责把doInBackground()方法中的耗时逻辑集成到Runnable中,才能作为参数传给线程池
private final FutureTask<Result> mFuture;
......
......
......
}
这个类里有两个线程池,都是static的,全局共享,一个负责存储Runnable对象,一个负责执行任务,为了方便后面描述,我们分别命名为“存储线程池”和“执行线程池”。
但是线程池只接收Runnable参数,所以需要一个Runnable对象把doInBackground()方法中的代码集成进去,这样才能被线程池接收。如何集成?就是在run()方法中调用耗时操作,但是问题又来了,如果把执行结果返回回去呢?
所以又需要WorkerRunnable对象,将耗时操作和执行结果返回封装一下,在run()方法中调用WorkerRunnable的call()方法。
再看构造方法:
public AsyncTask() {
// 初始化WorkerRunnable对象,封装耗时操作和执行结果
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;
}
};
// 初始化Runnable对象,与WorkerRunnable绑定,线程池中调用Runnable的run()方法时,就会调用WorkerRunnable的call()方法
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);
}
}
};
}
AsyncTask执行流程分析
AsyncTask有两个重载的execute()方法,一个是默认无参数的,一个是可以自定义Runnable的。先看默认无参数方法:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
// 将存储线程池作为参数,调用executeOnExecutor()方法
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()方法。这个方法是我们在实现AsyncTask时可以重写的方法,最早执行,用于做一些初始化操作,在UI线程中
onPreExecute();
// 将执行参数封装到WorkerRunnable对象中
mWorker.mParams = params;
// 调用存储线程池的execute()方法,将FutureTask插入存储线程池中
exec.execute(mFuture);
return this;
}
再看有参数、可以自定义Runnable的execute()方法:
public static void execute(Runnable runnable) {
// 同样,将runnabale插入存储线程池中。跟上面的区别就是,上面插入的Runnable对象是默认的,这里插入的Runnable对象是自定义的
sDefaultExecutor.execute(runnable);
}
最终都到了存储线程池sDefaultExecutor的execute()方法,我们看一下SerialExecutor类:
private static class SerialExecutor implements Executor {
// 使用数组队列存储Runnable
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
// 当前正在执行的Runnable
Runnable mActive;
public synchronized void execute(final Runnable r) {
// new要给Runnable,将新任务再次封装一次,插入到队列尾部
// 由于队列中的任务需要遵循某种逻辑才能依次执行,所以需要重新封装一次
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
// 如果当前Runnable为null,说明这是该应用第一次执行AsyncTask,需要执行scheduleNext()方法启动“执行线程池”
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
// 取出任务,使用执行线程池来执行任务
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
从上面的run()方法可以看出,如果是第一次,就调用scheduleNext()启动任务。如果不是第一次,就把新任务插入到存储线程池中。上一个任务执行完毕后,会调用scheduleNext()方法执行下一个任务。
这里需要注意的是,从doInBackground()到最终启动线程执行耗时操作,中间new了3个Runnable对象。
①第一个Runnable,是为了把doInBackground()中的逻辑代码封装到run()方法中,因为存储线程池SerialExecutor统一接收Runnable对象作为参数;
②第二个Runnable,是为了把耗时操作封装到固定逻辑的run()方法中,这样才能达到依次执行的逻辑;
③第三个Runnable,就是执行线程池中的,真正用来执行耗时操作的,这里会启动n个核心线程和n个非核心线程。
前两个Runnable都是为了代码的可扩展性和灵活性做的管道封装,这两个Runnable都不会调用start()方法启动,只是调用run()方法执行里面的代码而已。
不管怎样,最终都会调用FutureTask的run()方法:
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
// 这个callable就是前面mFuture = new FutureTask<Result>(mWorker)中的WorkerRunnable
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
// 调用WorkerRunnable的call()方法
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);
}
}
在执行线程池中,会在子线程中调用FutureTask的run()方法,而run()方法中又会调用WorkerRunnable的call()方法,所以call()方法是在子线程中调用的:
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
//调用doInBackground()方法
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
// 耗时操作执行完毕后通知结果
postResult(result);
}
return result;
}
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
// 通过Handler通知执行结果,这样就可以在主线程中得到执行结果了
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
我们在实现doInBackground()方法时,可以在其中调用publishProgress ()方法通知主线程执行进度:
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
// 同样,也是通过Handler通知执行进度的
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
另外,如果我们启动任务时,调用execute(Runnable runnable)方法,使用自定义的Runnable,那最终就只会调用自定义Runnable的run()方法,系统就无法帮我们回调doInbackGround()、postResult()方法,需要我们自己在run()方法中实现耗时操作的处理、结果返回的处理。