从0开始学安卓源码分析--AsyncTask源码
问题:
- 为什么一个AsyncTask只能被执行一次?
- 为什么AsyncTask是串行执行的, 不能并行吗?
- 为什么AsyncTask必须在UI线程中创建?
带着问题看源码, 稳.
看一个源码当然从其构造函数出发.
public AsyncTask(@Nullable Looper callbackLooper) {
// 这里是为什么需要在主线程创建的原因, 不然怎么去更新ui?
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
// WorkerRunnable实现callable接口并实现了它的call()方法
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);
}
}
};
}
在这个构造方法里可以看到doInBackground(mParams)
方法, 也就是我们继承AsyncTask
复写的方法. 该方法返回了result
结果, 最终在finally
里调用postResult(result);
将结果通过handler传递进行处理. 在handler的handleMessage中会调用AsyncTask
的finish()方法.
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
这里就找到了 onPostExecute(result);
将结果通过onPostExecute回调到上层了.
FutureTask
是一个可管理的任务类, 它实现了Runnable和Callable两个接口, 稍微瞄一眼源码可知其可以对Runnable和Callable进行包装.
这里将WorkerRunnable
作为入参传递给了FutureTask
.
AsyncTask
还并未开始执行, 真正执行需要调用AsyncTask.execute(params);
, 并将params传递进去.
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
接着看executeOnExecutor(sDefaultExecutor, params);
这里需要看下AsyncTask的三个状态:
- PENDING // 等待, 表示任务未执行
- RUNNING // 表示任务正在运行
- FINISHED // 表示任务已经完成结束
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
// 这里也是为什么一个AsyncTask只能执行一次的原因
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()方法, 我们会在onPreExecute进行一些不耗时初始化的操作
onPreExecute();
mWorker.mParams = params;
// 这里开始真正执行task任务
exec.execute(mFuture);
return this;
}
调用exec.execute(mFuture);
真正执行任务的exec
是什么呢?
是传递进来的sDefaultExecutor
.
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static class SerialExecutor implements Executor {
// ArrayDeque 先进先出的双端队列
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
// 先将任务都存入队列里
// 当前没有执行的任务则从队列中取出一个用THREAD_POOL_EXECUTOR执行.
// 当前有执行的任务则是在任务完成后的finally里取出一个执行
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
是一个静态的串行执行器, 也就是如果都调用AsyncTask.execute(params);
方法, 那么一个进程内所有AsyncTask都是由sDefaultExecutor
串行执行的. 这样保证一个时间只有一个任务执行.
如果需要并行执行任务则需要调用executeOnExecutor(Executor exec,Params... params)
另外注意再看看THREAD_POOL_EXECUTOR
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
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;
}
线程池用到了一个容量128的阻塞队列.
到这里我们继承AsyncTask需要复写的方法,就都已经在流程中出现了
- onPreExecute()
- doInBackground(params)
- onPostExecute(result)
还有另外一个onProgressUpdate(progress)
在哪儿呢?
搜索一下源码.
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
可以在doInBackground()
中调用publishProgress()
方法来进行进度的更新. 通过handler来将更新进度发布到UI线程并回调onProgressUpdate(progress)
方法
AsyncTask的源码到这里已经分析完了, 总的来说难度不大. 最后AsyncTask可能会导致内存泄漏, 记得适时的调用AsyncTask的cancel()方法