前言
AsyncTask的使用方法请看Android日记之AsyncTask的基本使用,此篇的源码解析我们还是从使用方法开始进行解析,源码版本基于Android9.0。
AsyncTask的工作原理
启动AsyncTask的方法是execute()
,我们从这里开始分析。
//sDefaultExecutor是线程池,第二个参数是执行异步的参数
@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;
}
从这里可以看出会先进行状态的判断,然后就会执行onPreExecute()
方法,这个方法会被最先执行,然后接下来线程池也会接着开始执行,就是exec.execute(mFuture)
,这里传入了一个mFuture对象,因为exec是sDefaultExecutor传进来的变量,我们就来看看sDefaultExecutor是哪里来的
...
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
...
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
...
这里先new出了一个SERIAL_EXECUTOR常量,然后将sDefaultExecutor的值赋值为这个常量,也就是说明,刚才在executeOnExecutor()方法中调用的execute()方法,其实也就是调用的SerialExecutor类中的execute()方法,我们就看看SerialExecutor类具体的execute()
实现。
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);
}
}
}
从这里可以看出,这里的方法开了一个Runnable,也就是说这里的方法开始是在子线程中开始进行的了,这里就可以看出AsyncTask的执行过程了,首先系统会把AsyncTask的Params参数封装成FutureTask对象,它是一个并发类对象,这里充当了Runnable的作用,然后将FutureTask交给SerialExecutor的execute()
进行处理,进入了这里之后,首先会将FutureTask对象插入到任务队列mTasks中,接着会判断mActive == null,就是这时候如果没有正在执行的AsyncTask任务的话,那么就会调用scheduleNext()
去执行下一个AsyncTask的任务,同时当一个任务执行完的话,就会接着执行下一个的任务,直到全部都被执行完毕为止,从这里也可以看出,AsyncTask是串行执行的。
接下来,我们还没找到doInBackground()
是从哪里实现的,我们接着看。其实在AsyncTask里面中有两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handler,SerialExecutor刚刚已经说过了,适用于任务的排队的,而THREAD_POOL_EXECUTOR就是去执行真正的任务。刚刚上面的代码Runnbale这里是有一个参数,这个参数其实就是FutureTask,也就是说这里的run()
方法其实就是调用FutureTask的run()
方法,而FutureTask的run()
又会调用mWorker的call()
方法,我们从AsyncTask的构造函数中中可以看到。
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
//这里new了一个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
//通过FutureTask的run方法开始执行doInBackground();
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
//这里new了一个FutureTask,参数为mWorker,也就是会执行mWorker的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);
}
}
};
}
从上面那段代码可以看出有个变量为mTaskInvoked,被设置为true,就是代表当前任务以及被调用了,然后开始执行doInBackground()
方法。返回值会传给postResult()
里面。
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
从这里也可以看看出,通过getHandler()
调用了AsyncTask里的Handler去进行发送。最后看AsyncTask的的结束逻辑,这里就比较简单了,如果AsyncTask被取消执行了,那么就调用onCancelled()
方法,否者就是调用onPostExecute()
方法,而这个返回结果就是doInBackground()
这个方法返回的,到这里就基本全部分析完毕了。
使用AsyncTask的注意事项
使用AsyncTask是有几个注意事项的,有以下几点:
- AsyncTask的类必须要在主线程进行开始加载,也就是说第一次访问AsyncTask必须发生在主线程,当然这个过程在Android 4.1以上已经被自动完成了。
- AsyncTask的对象必须要在主线程中创建。
-
execute()
方法必须在UI线程中调用。 - 不要再程序中直接调用
onPreExecute()
、onPostExecute()
、doInBackground()
和onProgressUpdate()
方法。 - 一个AsyncTask对象只能被执行一次,就是说
execute()
方法只能调用一次,否者会出现异常。 - 在Android1.6之前,AsyncTask是串行执行任务的,1.6的时候,编程了并行执行任务,3.0的时候为了避免并行出现的错误,就开始采用了一个线程来执行串行任务。虽然是这样子,但是我们依然可以通过
executeOnExecutor()
来并发执行任务。
参考
- Android AsyncTask完全解析,带你从源码的角度彻底理解
- [任玉刚] Android开发艺术探索
网友评论