前言: 5月份第一篇博客,第一次以自己的视角去分析源码,先看了大量大牛的文章。
AsyncTask是android提供我们方便使用异步任务的一个封装类,有了它,我们可以很方便的使用异步操作;但是作为一个合格的开发者,只会用并没有什么意义,我们当然要懂得它是怎么实现的,可以让我们这么方便的使用异步任务。
废话不多说,让我们从常用方法说起,因为是讨论源码,这些只是后面源码需要调用这些方法,提一下比较好。
AsyncTask4个核心方法:
- onPreExecute() :在成功调用execute后执行,用于一些准备操作
- doInBackground(Params… params):在onPreExecute()后的WorkerRunnable抽象类的实体类中调用,在执行中可以调用publishProgress(Progress… values)方法来更新进度。
- onProgressUpdate(Progress… values):在调用publishProgress后执行,此方法可以用来更新UI。
- onPostExecute(Result result):在任务执行结束后调用,如果任务已经结束则不会调用。
Android3.0之前使用的是并行处理。Android7.0后改为串行处理。这样保证了一个时间段只有一个任务执行。
1.从构造方法开始分析:
AsyncTask提供了3个构造方法,但最终都会调用参数最长的方法,因为其利用了自身回调的设计。
public AsyncTask() {
//调用下一个构造方法
this((Looper) null);
}
public AsyncTask(@Nullable Handler handler) {
//调用下一个构造方法
this(handler != null ? handler.getLooper() : null);
}
这样两个构造方法并没有什么实现的逻辑,我们来看看最后一个构造方法:
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);
//这里调用了doInBackground方法,并且传入了result的值
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
//最后调用了postResult方法
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);
}
}
};
}
这里定义了一个mFuture的FutureTask,FutureTask需要传入一个Callable接口,这里也实现了一个WorkerRunnable抽象类,我们看看这个类怎么定义的:
private static abstract class WorkerRunnable<Params, Result>
implements Callable<Result> {
Params[] mParams;
}
从这里我们可以知道WorkerRunnable是一个静态抽象类,并且实现了Callable接口,即是Callable接口的实体类。
所以从这里我们知道了mFuture = new FutureTask(mWorker)这里为什么要传入一个mWorker。为什么要定义一个WorkerRunnable类。
我们从这里也可以发现AsyncTask实现线程异步操作利用的正是多线程实现里的FutureTask+Callable接口这个组合(有不懂的可以看我上一篇博客)。
我们再来看看mWorker里的call()方法,里面我们发现了doInBackground方法原来是在这里被调用,我们还发现在finally代码块里有一个postResult(result)方法,看下这个方法的实现:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
//这里用message发消息给handler
Message message =
//发送执行完毕消息MESSAGE_POST_RESULT
getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
原来这个方法是用一个Message去给Handler发送消息,那既然是发送消息,我们肯定要去看看发了什么消息,我找到Hadler的具体实现位置,还记得构造方法里第一个mHandler的语句吗(我在下面再重新贴出来):
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper ==
Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
......
实现了方法getMainHandler():
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
这里使用单例设计模式,创建一个单例的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方法,原来消息在这里被接收,消息被接收之后,调用finish()方法去完成执行异步任务,看看finish()方法:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
我们看到这个有一个mStatus变量,这个变量是用来设置当前的状态,现在把状态设置为了Status.FINISHED,执行结束状态。并且我们发现会调用onPostExecute方法。
讲完这些后,我们发现有一个publishProgress没有分析,我们来看看publishProgress方法:
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
//同样是发送消息让handler接收
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>
(this, values)).sendToTarget();
}
}
我们会想起,之前那个InternalHandler类有一个switch语句块,我们看下:
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;
}
我们发现第二个就是接收publishProgress发送的消息,然后执行onProgressUpdate方法。看到这里我们明白了,为什么调用publishProgress就可以执行到onProgressUpdate更新UI进度。
看到这里不知道你有没有发现,消息里面都传入了一个 AsyncTaskResult类,我们来看下这个类:
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
是一个静态类;第一个参数是一个AsyncTask,第二个参数是通过泛型来传入的Data数组mData,类里只有一个构造方法来初始化参数。(因为InternalHandler为静态内部类,所以类中方法不能直接调用)
2.从提交方法execute()接着分析:
因为使用AsyncTask的使用就只是
new asyncTask().execute();
已经从构造方法分析完了new asyncTask(),那接下来当然要分析execute()方法,我们来看下源码:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
是调用了一个executeOnExecutor方法,我们接着看:
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方法
onPreExecute();
mWorker.mParams = params;
//执行mFuture
exec.execute(mFuture);
return this;
}
这里先判断异步任务是否已经在执行,不是就设置为正在执行,并且利用sDefaultExecutor线程池来执行mFuture。
我们来看看这个sDefaultExecutor参数的定义:
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
我可以发现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 {
//这个调用FutureTask的run方法最后调用WorkerRunnable的call方法
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
最后会回到调用FutureTask的run方法然后调用WorkerRunnable的call方法,最后调用postResult方法,之后就是前面的流程了。
最后我们看看scheduleNext()定义的这个线程池THREAD_POOL_EXECUTOR:
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
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 BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
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;
}
ThreadPoolExecutor的核心线程由CPU的核心数来计算得出。采用的队列是LinkedBlockingQueue,容量为128。
还有就是如果想要使用并行处理,可以使用下面代码:
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");
还可以利用这个executeOnExecutor方法传入自定义线的程池:
Executor exec = new ThreadPoolExecutor(......(需要自定义的参数));
asyncTask.executeOnExecutor(exec,"");
这次的AsyncTask源码分析就到这里了,有什么写的错误的地方希望指出,本人能力有限,文章难免有一些错误。
总结一下:
AsyncTask利用了FutureTask+Callable接口,利用线程池和阻塞队列来实现它的功能。其实AsyncTask就利用到了线程和线程池的知识,源码里还要一些静态内部类,单例设计,Message和Handler进行消息的传送这些知识,代码写的非常好,值得反复细读。