不知道为什么,最近感觉喜欢上了分析源码了。哈哈,今天我们分析一下AsyncTask的源码,来了解一下这个异步类的原理。
本文参考资料:
1. Java线程(七):Callable和Future
2.任玉刚老师的《Android 开发艺术探索》
由于AsyncTask类的源码设计Callable、Futrue类,可能难于理解(其实我也不太懂!),大家可以参考:Java线程(七):Callable和Future
1.概述
大家对于AsyncTask应该都不陌生,通常来说在异步加载的成功可能会使用到它,当然现在可能有很多的新东西可以来替代它。不过,我们来了解一下Google爸爸帮我们实现的功能,还是不错的。
在AsyncTask中有4个核心方法,分别是:
1.onPreExecute():在异步任务执行之前,这个方法会被回调,一般在这个方法里面初始化一些东西。这个方法在主线程中调用。
2.doInBackground(Params...params):在子线程中调用,此方法用来执行异步任务。在这个里面可以通过调用publishProgress方法来更新任务的进度,publishProgress会调用onPressUpdate方法。此方法需要返回结果给onPostExecute方法。
3.onProngressUpdate(Progress...values):当异步任务的进度发生改变时,会被调用。
4.onPostExecute(Result result):在异步执行完成之后,此方法会被调用,其中result参数是异步任务返回的结果,即doInBackground的返回值。
4个方法的执行顺序是:onPreExecute -> doInBackground ->onProngressUpdate ->onPostExecute。
简单的说了一下AsyncTask几个方法的作用,接下来将会从源码的角度上来看看AsyncTask的工作原理。
2.AsyncTask的分析
通常来说,我们在使用AsyncTask的时候,基本是如下的操作:
new AsyncTaskImpl().execute(...);
所以,我们先来AsyncTask的构造方法里面给我们创建了什么东西。
(1).构造方法
不管是哪个构造方法,最终会调用到这里来:
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);
//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);
}
}
};
}
我们还是那样,逐一的分析,首先来看看,创建的Handler:
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
这一句非常的简单就是给我们创建一个Handler,其中这个Handler带的Looper属于主线程。这里不对Handler作过多的解释,毕竟终点不是在这里。如果有不懂Handler的朋友,可以自行到网上去看看,你们在这里就把这个Handler当成我们在Activity中创建的一个Handler。
然后我们在看看这一句:
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;
}
};
首先,这里的WorkerRunnable是实现了Callable。至于这里的Callable是什么东西,大家可以参考: Java线程(七):Callable和Future。这里的简单的解释一下,Callable跟Runnable非常的像,都是用于线程的,只不过,Runnable的执行的run方法并且没有返回值,Callable执行的是call方法,并且有返回值;同时Runnable执行直接用于Thread来执行,Callable需要使用Futrue来封装一下。具体的用法,大家可以上面的文章。
不懂Callable接口的老哥也不用担心,这里我们只需要将它当成一个Runnable就行了,call方法就是线程需要执行的方法。我们在这个call方法看到了这一句:
result = doInBackground(mParams);
从这一句我们就知道,当一个线程启动了,调用了call方法了,就会调用doInBackground方法,执行我们的任务了。
最后再来看看Futrue的创建:
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);
}
}
};
可能又有老哥懵逼了,这特么又是什么东西。不急不急,我们分析一下FutrueTask是什么东西:
public class FutureTask<V> implements RunnableFuture<V>
额,还是不是很懂,我们再来RunnableFutrue接口:
public interface RunnableFuture<V> extends Runnable, Future<V>
这里应该差不多了,FutureTask根本就是一个Runnable,当放在Thread里面的时候,它的run方法肯定会被回调。但是Future又是干嘛用的,Futrue主要用来标记我们可以利用FutureTask来获取线程执行的结果。但是我们知道run返回值是void, 怎么能从run方法里面获取结果呢?实际上run方法也没有真正的执行,而是调用了Callable的call方法。我们来从源码看看:
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
runner = null;
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
上面的代码是FutrueTask里面的run方法,我们看到它调用了Callable的call方法。这个就能理解,为什么之前的call方法里面调用doInBackground方法了。
在FutrueTask的run方法里面还有这么一句代码:
if (ran)
set(result);
我们来看看set方法里面到底在干嘛了。
protected void set(V v) {
if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
outcome = v;
U.putOrderedInt(this, STATE, NORMAL); // final state
finishCompletion();
}
}
好嘛,又调用了finishCompletion方法,我们再来看看这个方法里面在干嘛:
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
if (U.compareAndSwapObject(this, WAITERS, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
q.thread = null;
LockSupport.unpark(t);
}
WaitNode next = q.next;
if (next == null)
break;
q.next = null; // unlink to help gc
q = next;
}
break;
}
}
done();
callable = null; // to reduce footprint
}
这里需要注意这一句:
done();
哈哈,我们终于看到done方法了。也就是当在FutrueTask的run方法成功的获取执行的结果之后,随后会调用done方法。
到这里,可能有老哥有点懵逼了。我来解释一下:
1.首先,创建一个Callable的对象,在Callable对象的call方法里面执行了真正需要执行的任务。
2.然后我们创建Runnable的一个实现类的对象,在这个类的run方法实际上调用了Callable的call方法来执行任务,然后将结果返回,最后调用done方法表示任务结束了。
这里我画一个图来解释一下整个流程:
AsyncTask的构造方法我们理解的差不多了,在这里,做一个简单的总结:
1.创建了一个带主线程的LooperHandler。这里的作用很明显,就是进行线程的调度。
2.创建Callable对象,并且在call方法里面调用,这个方法真正执行了任务,因为在call方法里面调用了doInBackground方法。
3.创建了FutrueTask对象,在它的done方法里面调用了FutrueTask的get方法,来获取任务执行的结果。
整个任务的传递流程在上面的已经解释的比较清楚了,如果还有不懂的老哥,建议大家看看源码,这样比较直观。
(2).execute方法
在构造方法里面,已经为我们创建了三个对象供我们使用。我们需要执行任务,真正调用的execute方法。现在我们来看看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();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
这里我们需要注意地方。我们来一一分析:
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)");
}
}
意思很明白,只要AsyncTask的状态不是PENDING,也就是预备状态,都会跑出异常。这个就能解释为什么AsyncTask只能使用一次。
在这里,我们还看到了另一个核心方法:
onPreExecute();
由于这里还是在主线程,所以,我们就能理解onPreExecute在主线程执行。
最后调用的是:
exec.execute(mFuture);
特么的,这个exec又是什么东西。我们还是看看调用这个构造方法到底传入的是什么参数。从execute方法里面,我们得到的信息是,exec就是sDefaultExecutor。这个sDefaultExecutor又是什么东西:
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
public static final Executor SERIAL_EXECUTOR = new 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接口不熟悉。这里不需要深入的理解Executor 是什么东西,暂且将它当成一个线程池。所以,实际上sDefaultExecutor 是一个线程池。
在这里线程池里面,我们需要注意的是,线程池持有一个ArrayDeque的队列,在execute方法里面我们可以看到,实际上将这个Runnable的入队了。
同时,如果mActive 为null的话,会调用scheduleNext方法从队列里面去取任务来执行。
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
这个THREAD_POOL_EXECUTOR又是什么,我们从这个变量的初始化阶段来看看:
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;
}
实际上,THREAD_POOL_EXECUTOR 也是一个线程池。而这里调用线程池的execute方法就是将任务提交到线程池里面去,让线程池来执行我们的任务。
因此,我们从AsyncTask的executeOnExecutor方法里面可以得到信息。当用户提交一个任务过来时,实际上是让线程池来帮我们执行的。
在这里,我来画一个图来解释整个的执行流程:
这里还是做一个简单的总结:
1.整个execute的流程中,有两个线程池,一个线程池使用了队列来存储任务,另一个线程池来执行任务。
2.执行任务实际上调用的是Callable的call方方法,进而执行doInBackground方法
3.当doInBackGround方法执行完毕之后,会调用done方法。
(3).onPostExecute方法
核心方法我们已经看到了两个了,onPreExecute方法在executeOnExecutor方法中调用,doInBackground方法在Callable的call方法里面被调用,还有两个方法我们不知道。这里我们先来看看onPostExecute方法,因为onProgressUpdate方法需要我们在doInBackground方法里面调用publishProgress方法才会被调用,这里先不对其进行分析。
我们知道,当一个任务执行完毕之后,会调用FutrueTask的done方法,我们再来看看done方法:
@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);
}
}
好嘛,调用了postResultIfNotInvoked方法:
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
最后我们在postResult方法里发现,它通过Handler将这个resutl发送出去了。由于这个操作会回调Handler里面去,我们来看看Handler:
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;
}
}
}
我们发现,只要表示任务结束的话,会调用AsyncTask的finish方法:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
哈哈,我们终于知道onPostExecute的执行流程了。总结一下就是,当一个任务执行完毕之后,会通过Handler来进行线程的调度,切换到主线程,从而在主线程调用onPostExecute方法。
(4).onProgressUpdate方法
最后,我们再来看看onProgressUpdate的方法的执行流程。由于onProgressUpdate执行时机是,在doInBackground方法调用了publishProgress方法,所以我们还是先来看看publishProgress方法:
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
哎呀,简单到不能再简单了,就是通过Handler来发送Message。在这个之前,我们在Handler的handlerMessage方法里面看到:
result.mTask.onProgressUpdate(result.mData);
这里就完成了onProgressUpdate的回调。
3.总结
总的来说,AsyncTask还是比较简单的,最后对AsyncTask做一个简单的总结: