这篇文章中,让咱们从源码的角度看一下AsyncTask
的原理,最后会根据原理总结一下使用AsyncTask
中须要注意的点。android
在AsyncTask
中,有一个线程池 THREAD_POOL_EXECUTOR
和与这个线程池相关联的 Executor
,它负责执行咱们的任务Runnable
:bash
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;
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);
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
//这是执行Runnable的地方,调用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();
}
}
});
//若是为null,那么马上执行它;
//若是不为null,说明当前队列中还有任务,那么等Runnable执行完以后,再由上面的scheduleNext()执行它。
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
//第一次进来调用了offer方法,所以会走进去,执行上面Runnable的run()方法。
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
复制代码
从上面能够看出,每次调用sDefaultExecutor.execute
时就是执行一个任务,这个任务会被加入到ArrayDeque
中串行执行,咱们看一下当咱们调用AsyncTask
的execute
方法时,任务是如何被建立并加入到这个队列当中的:ide
//这个静态方法,不会回调 loadInBackground 等方法。
public static void execute(Runnable runnable) {
sDefaultExecutor.execute(runnable);
}
//这是咱们最常使用的方法,参数能够由调用者任意指定。
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
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();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
复制代码
在调用了executeOnExecutor
以后,咱们把传入的参数赋值给了mWorker
,并把mFuture
传入给Executor
去执行,而从下面咱们能够看到mFuture
的构造函数中传入的参数正是mWorker
,这两个东西其实才是AsyncTask
的核心,它们是在AsyncTask
的构造函数中被初始化的:函数
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
//要求mWorker的call方法没有被调用,不然什么也不作。
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);
}
}
};
复制代码
先看一下WorkerRunnable
,实现了Callable<V>
接口,增长了一个不定参数的成员变量用来传给 doInBackground
,这个不定参数就是咱们在execute
时传入的,调用call
时会执行器内部的函数,而call
时会调用doInBackground
方法,这个方法执行完以后,调用postResult
,注意到call
和done
都是在子线程当中执行的:源码分析
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
复制代码
咱们主要看一下FutureTask
,还记得最开始咱们的Executor
最终执行的是传入的Runnable
的run
方法,所以咱们直接看一下它的run
方法中作了什么:post
public interface Runnable {
public void run();
}
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
//咱们只要关注run方法
public class FutureTask<V> implements RunnableFuture<V> {
public void run() {
Callable<V> c = callable;
if (c != null && state == NEW) {
result = c.call(); //mWorker.call()
ran = true;
}
if (ran) {
set(result);
}
}
protected void set(V v) {
finishCompletion();
}
private void finishCompletion() {
done(); //mFuture.done()
callable = null;
}
}
复制代码
那么结论就清晰了,整个的执行过程是下面这样的:ui
excuter.execute(mFuture)
,把mFuture
加入到队列当中mFuture
获得执行时,会回调mFuture
的run
方法mFuture#run
是运行在子线程当中的,它在它所在的线程中执行的mWorker#call
方法mWorkder#call
调用了doInBackground
,用户经过实现这个抽象方法来进行耗时操做mFuture#call
执行完后调用mFuture#done
在上面的过程中,有两个地方都调用了postResult
,一个是mWorkder#call
的最后,另外一个是mFuture#done
,可是区别在于后者在调用以前会判断mTaskInvoked
为false
时才会去执行,也就是在mWorkder#call
没有执行的状况下,这是为了不call
方法没有被执行时(提早取消了任务),postResult
没有被执行,致使使用者收不到任何回调。 postResult
会经过InternalHandler
把当前的AsyncTask
和FutureTask
的结果回调到主线程当中,以后调用finish
方法,它会根据调用者是否执行过cancel
方法来回调不一样的函数:this
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
复制代码
调用者经过重写onProgressUpdate
就能够获得当前的最新进度,AsyncTask
最终会把结果回调到主线程当中:spa
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
private static class InternalHandler extends Handler {
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;
}
}
}
复制代码
通过上面的源码分析,咱们有这么几个结论:线程
execute(Runnable runnable)
和AsyncTask
其实没什么太大关系,只是用到了里面一个静态的线程池而已,AsyncTask
内部的状态都和它无关。AsyncTask
实例调用execute(..)
时,若是此时已经有任务正在执行,或者已经执行过任务,那么会抛出异常。onPreExecute()
执行时,任务尚未被加入到队列当中。doInBackground
是在子线程当中执行的,咱们调用cancel
后,并不必定会当即获得onCancel
的回调,这是由于cancel
只保证了mFuture
的done
方法被执行,有这么几种状况:mWorker
的call
函数没有执行,那么这时mFuture
的done
方法被调用时,postResultIfNotInvoked
是知足条件的,调用者能够当即获得onCancel
回调。mWorker
的call
调用了,虽然mFuture
的done
执行了,可是它不知足条件(!mTaskInvoked.get())
,那么会一直等到doInBackground
执行完全部的操做才经过return postResult
返回,因此咱们须要在doInBackground
中经过isCancel()
来判断是否须要提前返回,避免无用的等待。postResult
完毕以后, onCancel
和onPostExecute
只会调用一个。AsyncTask
实例绑定的,而若是AsyncTask
又和Activity
绑定了,若是在执行过程当中这个 AsyncTask
实例被销毁了(例如Activity
被从新建立),那么调用者在新的Activity
中是没法收到任何回调的,由于那已是另一个AsyncTask
了。AsyncTask
最大的问题实际上是内存泄漏,由于把它做为Activity
的内部类时,会默认持有Activity
的引用,那么这时候若是有任务正在执行,那么 Activity 是没法被销毁的,这其实和Handler
的泄漏相似,能够有如下这么一些用法:Activity
的引用或者持有弱引用。Activity
在须要销毁时cancel
了全部的任务。AsyncTask
的执行与Activity
的生命周期无关,能够考虑经过创建一个没有UI
的fragment
来实现,由于在Activity
重启时,会自动保存有以前add
进去的Fragment
的实例,Fragment
持有的仍是先前的 AsyncTask
。LoaderManager
,把管理的活交给系统来执行。