构造AsyncTask, 这里只需理解Worker, Future的概念。注意这里mWorker 和 mFuture 的关系, 以及 postResult 和done方法。
AsyncTask使用了模板方法的设计模式, doInBackground是其中的核心,被包装在mWorker对象中,mWorker对象又被包装在mFuture对象, mFuture本质是一个runnable
/** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. */ public AsyncTask() { mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked return postResult(doInBackground(mParams)); } }; 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 occured while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } } }; }
===============以上是背景。==================
从execute方法开始,内部调用了executeOnExecutor 方法,
public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
这里的sDefaultExecutor 默认是SERIAL_EXECUTOR,是 SerialExecutor类型对象。 模板方法doInBackground的参数params就是在这里通过mWorker对象赋值的
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) { ... mStatus = Status.RUNNING; onPreExecute(); mWorker.mParams = params; exec.execute(mFuture); return this; }
AsyncTask中有两个重要的静态变量:SERIAL_EXECUTOR 和 THREAD_POOL_EXECUTOR
/** * An {@link Executor} that can be used to execute tasks in parallel. */ public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); /** * An {@link Executor} that executes tasks one at a time in serial * order. This serialization is global to a particular process. */ public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
接下来看 SerialExecutor 的execute 方法, 先把当前task放在队列mTasks尾部,然后取队列第一个task通过TREAD_POOL_EXECUTOR执行。 注意execute 和 scheduleNext 都是synchronized 方法, 在AysncTask中SerialExecutor的实例变量SERIAL_EXECUTOR又是一个静态成员,所以即使我们在不同的线程中new出来很多AyncTask对象分别提交不同的任务, 这些任务让仍然会被串行的加入任务队列。
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(); } } }); //如果当前没有正在执行的任务就在队首调度一个新任务, //否则等待当前任务完成,完成后会自动调度下一个任务, 这里的mActive是包装后的任务对象 if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { // SERIAL_EXECUTOR调用了THREAD_POOL_EXECUTOR来具体执行任务 //注意这里的mActive是包装后的任务对象 THREAD_POOL_EXECUTOR.execute(mActive); } } }
千万注意,这里我们提交的任务是 r , 但是在放入mTasks队列时对 r 进行了如下的包装, 这里包装后的任务对象是匿名的,假设包装后的任务叫pr ( pseudo r 的意思) , 那么pr 的执行包括了两部分,首先执行具体的任务(r的run方法),然后不管任务执行是否成功(也就是不管r的run方法过程是否发生了异常),接着调度mTasks队列的下一个任务。所以当使用默认的AsyncTask时,如果有多处提交任务,那么这些任务将会按串行的方式执行,这就是为什么官方推荐只用AsyncTask执行短时任务, 任务耗时太长的话将会发生相互阻塞,这可能是你不想要的!
mTasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } });
问题到这里已经清楚了。
=================end======================
接着说一下, TREAD_POOL_EXECUTOR 和 SERIAL_EXECUTOR都可以当做executor使用, 并且TREAD_POOL_EXECUTOR是可以并行的执行任务的(多线程),但是TREAD_POOL_EXECUTOR对AsyncTask是不可见的,SERIAL_EXECUTOR才是AsyncTask直接使用的executor对象。 TREAD_POOL_EXECUTOR只是作为SERIAL_EXECUTOR执行任务的工具,对SERIAL_EXECUTOR来说,它的作用就是可以提供线程来执行任务。所以如果你想改变AsyncTask不适合执行长时间任务的这个缺陷,需要定制自己的Executor来替换SERIAL_EXECUTOR。